//
// Copyright 2019 ZetaSQL Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include <math.h>

#include <array>
#include <limits>
#include <memory>
#include <numeric>
#include <string>
#include <utility>
#include <vector>

#include "zetasql/base/logging.h"
#include "google/protobuf/wrappers.pb.h"
#include "zetasql/compliance/functions_testlib_common.h"
#include "zetasql/public/functions/date_time_util.h"
#include "zetasql/public/numeric_value.h"
#include "zetasql/public/options.pb.h"
#include "zetasql/public/type.h"
#include "zetasql/public/types/type_factory.h"
#include "zetasql/public/value.h"
#include "zetasql/testing/test_function.h"
#include "zetasql/testing/test_value.h"
#include "zetasql/testing/using_test_value.cc"
#include <cstdint>
#include "absl/strings/cord.h"
#include "absl/strings/string_view.h"
#include "zetasql/base/status.h"

namespace zetasql {
namespace {
constexpr absl::StatusCode INVALID_ARGUMENT =
    absl::StatusCode::kInvalidArgument;
constexpr absl::StatusCode OUT_OF_RANGE = absl::StatusCode::kOutOfRange;
}  // namespace

std::vector<QueryParamsWithResult> GetFunctionTestsAnd() {
  return {
    // Binary.
    {{False(), False()}, False()},
    {{False(), True()}, False()},
    {{True(), False()}, False()},
    {{True(), True()}, True()},
    {{True(), NullBool()}, NullBool()},
    {{NullBool(), True()}, NullBool()},
    {{False(), NullBool()}, False()},
    {{NullBool(), False()}, False()},
    {{NullBool(), NullBool()}, NullBool()},
    // Ternary. The third argument affects the result.
    {{True(), True(), NullBool()}, NullBool()},
    {{True(), True(), False()}, False()},
    {{True(), NullBool(), False()}, False()}
  };
}

std::vector<QueryParamsWithResult> GetFunctionTestsOr() {
  return {
    // Binary.
    {{False(), False()}, False()},
    {{False(), True()}, True()},
    {{True(), False()}, True()},
    {{True(), True()}, True()},
    {{True(), NullBool()}, True()},
    {{NullBool(), True()}, True()},
    {{False(), NullBool()}, NullBool()},
    {{NullBool(), False()}, NullBool()},
    {{NullBool(), NullBool()}, NullBool()},
    // Ternary. The third argument affects the result.
    {{False(), False(), True()}, True()},
    {{False(), False(), NullBool()}, NullBool()},
    {{False(), NullBool(), True()}, True()}
  };
}

std::vector<QueryParamsWithResult> GetFunctionTestsNot() {
  return {
    {{False()}, True()},
    {{True()}, False()},
    {{NullBool()}, NullBool()}
  };
}

// Note that many array tests are generated by taking non-array tests
// and wrapping the values in arrays for the comparison.  This function
// returns test cases that aren't covered by those tests, such as
// NULL array values, arrays with different lengths, arrays with elements
// that are NULLs and NaNs, etc.  So for instance, these tests use
// ARRAY<DOUBLE> in order to test NaN behavior, and arrays with other
// element types are not covered here.
//
// The test result can be UNEQUAL, which in this case indicates that the
// two arrays compares as NOT EQUAL, but it cannot be determined if one
// array is LESS than the other.  For example, consider the comparison between:
//
// [NULL]
// [1, 2]
//
// We know these arrays are NOT EQUAL since they have different lengths.  But
// LESS comparison returns NULL because the comparison between the first
// element in the two arrays results in NULL.
static std::vector<ComparisonTest> GetArrayComparisonTests() {
  const Value null_array = Value::Null(DoubleArrayType());
  const Value empty_array = Value::EmptyArray(DoubleArrayType());

  const Value array0 = values::Array(DoubleArrayType(), {Value::NullDouble()});
  const Value array1 = values::DoubleArray({0});
  const Value array2 = values::DoubleArray({1});
  const Value array3 = values::Array(DoubleArrayType(),
                                     {Value::Double(1), Value::NullDouble()});
  const Value array4 = values::DoubleArray({1, 0});
  const Value array5 = values::DoubleArray({1, 1});
  const Value array6 = values::DoubleArray({2});

  const Value array7 = values::Array(DoubleArrayType(),
                                     {Value::Double(1), Value::NullDouble(),
                                      Value::Double(0)});
  const Value array8 = values::Array(DoubleArrayType(),
                                     {Value::Double(1), Value::NullDouble(),
                                      Value::Double(1)});
  const Value array9 = values::DoubleArray({1, 1, 1});

  const Value array_nan1 = values::DoubleArray({double_nan});
  const Value array_nan2 = values::DoubleArray({0, double_nan});
  const Value array_nan3 = values::DoubleArray({1, double_nan});
  const Value array_nan4 = values::DoubleArray({1, double_nan, 0});
  const Value array_nan5 = values::DoubleArray({1, double_nan, 1});

  std::vector<ComparisonTest> v = {
    // same null array, compare as NULL for both equality and non-equality.
    {null_array, null_array, NULL_VALUE},

    // same non-null array
    {empty_array, empty_array, EQUAL},
    {array1, array1, EQUAL},
    {array4, array4, EQUAL},

    // same array with null elements
    {array0, array0, NULL_VALUE},
    {array3, array3, NULL_VALUE},

    // null array and non-null array
    {null_array, empty_array, NULL_VALUE},
    {null_array, array0, NULL_VALUE},
    {null_array, array1, NULL_VALUE},
    {null_array, array3, NULL_VALUE},

    // empty array an non-empty array
    {empty_array, array0, LESS},
    {empty_array, array1, LESS},
    {empty_array, array2, LESS},
    {empty_array, array3, LESS},
    {empty_array, array4, LESS},
    {empty_array, array5, LESS},
    {empty_array, array6, LESS},

    // An array with the first NULL element compares as NULL with all
    // other arrays with at least one element.
    {array0, array1, NULL_VALUE},
    {array0, array2, NULL_VALUE},
    {array0, array3, UNEQUAL},  // We do know these are not equal because
    {array0, array4, UNEQUAL},  // array lengths are not equal, but for
    {array0, array5, UNEQUAL},  // LESS/GREATER the result is NULL.
    {array0, array6, NULL_VALUE},

    {array1, array2, LESS},
    {array1, array3, LESS},
    {array1, array4, LESS},
    {array1, array5, LESS},
    {array1, array6, LESS},

    {array2, array3, LESS},
    {array2, array4, LESS},
    {array2, array5, LESS},
    {array2, array6, LESS},

    {array3, array4, NULL_VALUE},
    {array3, array5, NULL_VALUE},
    {array3, array6, LESS},
    {array3, array7, UNEQUAL},
    {array3, array8, UNEQUAL},
    {array3, array9, UNEQUAL},

    {array4, array5, LESS},
    {array4, array6, LESS},

    {array5, array6, LESS},

    {array7, array8, UNEQUAL},
    {array7, array9, UNEQUAL},

    {array8, array9, NULL_VALUE},

    // Comparing NaN to a NULL returns NULL, comparing NaN to non-NULL
    // returns FALSE (including comparing NaN to NaN).
    {array_nan1, array0, NULL_VALUE},
    {array_nan1, array3, UNORDERED},
    {array_nan1, array6, UNORDERED},
    {array_nan1, array_nan1, UNORDERED},
    {array_nan1, array_nan2, UNORDERED},
    {array_nan1, array_nan3, UNORDERED},
    {array_nan1, array_nan4, UNORDERED},
    {array_nan1, array_nan5, UNORDERED},

    {array_nan2, array0, UNEQUAL},
    {array_nan2, array3, LESS},
    {array_nan2, array6, LESS},
    {array_nan2, array_nan2, UNORDERED},
    {array_nan2, array_nan3, LESS},
    {array_nan2, array_nan4, LESS},
    {array_nan2, array_nan5, LESS},

    {array_nan3, array0, UNEQUAL},
    {array_nan3, array3, NULL_VALUE},
    {array_nan3, array6, LESS},
    {array_nan3, array_nan3, UNORDERED},
    {array_nan3, array_nan4, UNORDERED},
    {array_nan3, array_nan5, UNORDERED},

    {array_nan4, array0, UNEQUAL},
    {array_nan4, array3, UNEQUAL},
    {array_nan4, array6, LESS},
    {array_nan4, array_nan4, UNORDERED},
    {array_nan4, array_nan5, UNORDERED},
  };

  return v;
}

// Only struct equality/inequality is defined for ZetaSQL, not other
// comparisons (less than, etc.).  Therefore all tests should be defined
// as EQUAL, UNORDERED (not equal), or NULL_VALUE.
static std::vector<ComparisonTest> GetStructComparisonTests() {
  const StructType* struct_type = SimpleStructType();  // a: string, b: int32_t
  const Value struct0 = Value::Struct(struct_type, {String("foo"), Int32(0)});
  const Value struct1 = Value::Struct(struct_type, {String("bar"), Int32(1)});
  const Value struct_with_null2 =
      Value::Struct(struct_type, {NullString(), Int32(1)});
  const Value struct_with_null3 =
      Value::Struct(struct_type, {String("bar"), NullInt32()});
  const Value struct_with_null4 =
      Value::Struct(struct_type, {NullString(), NullInt32()});
  const Value null_struct = Value::Null(struct_type);

  // a: string, b: {a: string b: int32_t}
  const StructType* nested_struct_type;
  ZETASQL_CHECK_OK(type_factory()->MakeStructType(
      {{"a", StringType()}, {"b", struct_type}}, &nested_struct_type));
  const Value null_nested_struct = Value::Null(nested_struct_type);
  const Value nested_struct1 =
      Value::Struct(nested_struct_type, {String("x"), struct1});
  const Value nested_struct1b =
      Value::Struct(nested_struct_type, {String("x"), struct1});
  const Value nested_struct_null1 =
      Value::Struct(nested_struct_type, {NullString(), struct1});
  const Value nested_struct_null2 =
      Value::Struct(nested_struct_type, {String("x"), struct_with_null2});
  const Value nested_struct_null3 =
      Value::Struct(nested_struct_type, {String("x"), struct_with_null3});
  const Value nested_struct_null4 =
      Value::Struct(nested_struct_type,
        {String("x"), Value::Null(struct_type)});

  // These DCHECKs are only here to more clearly show the contents of
  // all the struct values.
  DCHECK_EQ("(\"foo\", 0)",    struct0.GetSQLLiteral());
  DCHECK_EQ("(\"bar\", 1)",    struct1.GetSQLLiteral());
  DCHECK_EQ("(NULL, 1)",       struct_with_null2.GetSQLLiteral());
  DCHECK_EQ("(\"bar\", NULL)", struct_with_null3.GetSQLLiteral());
  DCHECK_EQ("(NULL, NULL)",    struct_with_null4.GetSQLLiteral());
  DCHECK_EQ("NULL",            null_struct.GetSQLLiteral());

  DCHECK_EQ("NULL",                     null_nested_struct.GetSQLLiteral());
  DCHECK_EQ("(\"x\", (\"bar\", 1))",    nested_struct1.GetSQLLiteral());
  DCHECK_EQ("(\"x\", (\"bar\", 1))",    nested_struct1b.GetSQLLiteral());
  DCHECK_EQ("(NULL, (\"bar\", 1))",     nested_struct_null1.GetSQLLiteral());
  DCHECK_EQ("(\"x\", (NULL, 1))",       nested_struct_null2.GetSQLLiteral());
  DCHECK_EQ("(\"x\", (\"bar\", NULL))", nested_struct_null3.GetSQLLiteral());
  DCHECK_EQ("(\"x\", NULL)",            nested_struct_null4.GetSQLLiteral());

  std::vector<ComparisonTest> v = {
    // same non-null struct
    {struct0, struct0, EQUAL},                 // (foo, 0) vs. (foo, 0)
    {struct1, struct1, EQUAL},                 // (bar, 1) vs. (bar, 1)

    // different non-null struct
    {struct0, struct1, UNORDERED},             // (foo, 0) vs. (bar, 1)

    // null struct and non-null struct
    {null_struct, struct1, NULL_VALUE},        // NULL vs. (bar, 1)

    // non-null struct vs. struct with a null field
    {struct0, struct_with_null2, UNORDERED},   // (foo, 0) vs. (NULL, 1)
    {struct1, struct_with_null2, NULL_VALUE},  // (bar, 1) vs. (NULL, 1)
    {struct0, struct_with_null3, UNORDERED},   // (foo, 0) vs. (bar, NULL)
    {struct1, struct_with_null3, NULL_VALUE},  // (bar, 1) vs. (bar, NULL)
    {struct0, struct_with_null4, NULL_VALUE},  // (foo, 0) vs. (NULL, NULL)
    {struct1, struct_with_null4, NULL_VALUE},  // (bar, 1) vs. (NULL, NULL)

    // null struct vs. struct with null field
    {null_struct, struct_with_null2, NULL_VALUE},  // NULL vs. (NULL, 1)
    {null_struct, struct_with_null3, NULL_VALUE},  // NULL vs. (bar, NULL)
    {null_struct, struct_with_null4, NULL_VALUE},  // NULL vs. (NULL, NULL)

    // null struct vs. same null struct
    {null_struct, null_struct, NULL_VALUE},        // NULL vs. NULL

    // Nested structs
    {nested_struct1, nested_struct1, EQUAL},   // (x, (bar, 1)) v. (x, (bar, 1))
    {nested_struct1, nested_struct1b, EQUAL},  // (x, (bar, 1)) v. (x, (bar, 1))

    // (x, (bar, 1)) vs. NULL
    {nested_struct1, null_nested_struct, NULL_VALUE},

    // (x, (bar, 1)) vs. struct with null
    {nested_struct1, nested_struct_null1, NULL_VALUE},  // (NULL, (bar, 1))
    {nested_struct1, nested_struct_null2, NULL_VALUE},  // (x, (NULL, 1))
    {nested_struct1, nested_struct_null3, NULL_VALUE},  // (x, (bar, NULL))
    {nested_struct1, nested_struct_null4, NULL_VALUE},  // (x, NULL)

    // struct with null vs. same struct with null
    {null_nested_struct, null_nested_struct, NULL_VALUE},
    {nested_struct_null1, nested_struct_null1, NULL_VALUE},
    {nested_struct_null2, nested_struct_null2, NULL_VALUE},
    {nested_struct_null3, nested_struct_null3, NULL_VALUE},
    {nested_struct_null4, nested_struct_null4, NULL_VALUE},

    // struct with null vs. different struct with null
    {null_nested_struct, nested_struct_null1, NULL_VALUE},
    {nested_struct_null1, nested_struct_null2, NULL_VALUE},
    {nested_struct_null2, nested_struct_null3, NULL_VALUE},
    {nested_struct_null3, nested_struct_null4, NULL_VALUE},
    {nested_struct_null4, null_nested_struct, NULL_VALUE},
  };
  return v;
}

static std::vector<ComparisonTest> GetComparisonTests(
    bool include_struct_comparisons, bool include_array_comparisons,
    bool include_nano_timestamp) {
  const Value enum0 = Value::Enum(TestEnumType(), 0);
  const Value enum1 = Value::Enum(TestEnumType(), 1);
  std::vector<ComparisonTest> v = {
      // bool
      {True(), True(), EQUAL},
      {False(), False(), EQUAL},
      {False(), True(), LESS},
      {True(), NullBool(), NULL_VALUE},

      // double
      {3.14, 3.14, EQUAL},
      {2.72, 3.14, LESS},
      {-3.14, -2.72, LESS},
      {-2.72, 3.14, LESS},
      {3.14, NullDouble(), NULL_VALUE},
      {NullDouble(), 3.14, NULL_VALUE},
      {0.0, 0.0, EQUAL},
      {0.0, double_pos_inf, LESS},
      {double_neg_inf, 0.0, LESS},
      {double_neg_inf, double_pos_inf, LESS},
      {double_pos_inf, double_pos_inf, EQUAL},
      {0.0, double_nan, UNORDERED},
      {double_nan, 0.0, UNORDERED},
      {double_pos_inf, double_nan, UNORDERED},
      {double_neg_inf, double_nan, UNORDERED},
      {double_nan, double_pos_inf, UNORDERED},
      {double_nan, double_neg_inf, UNORDERED},
      {double_nan, double_nan, UNORDERED},
      {double_nan, NullDouble(), NULL_VALUE},
      {NullDouble(), double_nan, NULL_VALUE},
      {double_neg_inf, NullDouble(), NULL_VALUE},
      {NullDouble(), double_neg_inf, NULL_VALUE},
      {double_pos_inf, NullDouble(), NULL_VALUE},
      {NullDouble(), double_pos_inf, NULL_VALUE},

      // float
      {3.14f, 3.14f, EQUAL},
      {2.72f, 3.14f, LESS},
      {-3.14f, -2.72f, LESS},
      {-2.72f, 3.14f, LESS},
      {3.14f, NullFloat(), NULL_VALUE},
      {NullFloat(), 3.14f, NULL_VALUE},
      {0.0f, 0.0f, EQUAL},
      {0.0f, float_pos_inf, LESS},
      {float_neg_inf, 0.0f, LESS},
      {float_neg_inf, float_pos_inf, LESS},
      {float_pos_inf, float_pos_inf, EQUAL},
      {0.0f, float_nan, UNORDERED},
      {float_nan, 0.0f, UNORDERED},
      {float_pos_inf, float_nan, UNORDERED},
      {float_neg_inf, float_nan, UNORDERED},
      {float_nan, float_pos_inf, UNORDERED},
      {float_nan, float_neg_inf, UNORDERED},
      {float_nan, float_nan, UNORDERED},
      {float_nan, NullFloat(), NULL_VALUE},
      {NullFloat(), float_nan, NULL_VALUE},
      {float_neg_inf, NullDouble(), NULL_VALUE},
      {NullDouble(), float_neg_inf, NULL_VALUE},
      {float_pos_inf, NullDouble(), NULL_VALUE},
      {NullDouble(), float_pos_inf, NULL_VALUE},

      // int32_t
      {0, int32max, LESS},
      {int32min, int32max, LESS},
      {1, 1, EQUAL},
      {1, 2, LESS},
      {-2, -1, LESS},
      {-1, 1, LESS},
      {1, NullInt32(), NULL_VALUE},

      // int64_t
      {0ll, int64max, LESS},
      {int64min, int64max, LESS},
      {1ll, 1ll, EQUAL},
      {1ll, 2ll, LESS},
      {-2ll, -1ll, LESS},
      {-1ll, 1ll, LESS},
      {1ll, NullInt64(), NULL_VALUE},

      // uint32_t
      {0u, uint32max, LESS},
      {0u, 1u, LESS},
      {0u, uint32max, LESS},
      {1u, 1u, EQUAL},
      {0u, 2u, LESS},
      {1u, NullUint32(), NULL_VALUE},

      // uint64_t
      {0ull, uint64max, LESS},
      {0ull, 1ull, LESS},
      {0ull, uint64max, LESS},
      {1ull, 1ull, EQUAL},
      {0ull, 2ull, LESS},
      {1ull, NullUint64(), NULL_VALUE},

      // int64_t vs. uint64_t
      {0ll, 0ull, EQUAL},
      {int64max, Uint64(int64max), EQUAL},
      {0ll, Uint64(int64max), LESS},
      {-1ll, 0ull, LESS},
      {0ll, 1ull, LESS},
      {0ull, 1ll, LESS},
      {int64max, int64max_plus_one, LESS},
      {-1ll, int64max_plus_one, LESS},
      {-1ll, NullUint64(), NULL_VALUE},
      {1ull, NullInt64(), NULL_VALUE},

      // numeric
      {Numeric(0), NumericValue::MaxValue(), LESS},
      {NumericValue::MinValue(), NumericValue::MaxValue(), LESS},
      {Numeric(1), Numeric(1), EQUAL},
      {NumericFromDouble(123.456), NumericFromDouble(123.654), LESS},
      {NumericFromDouble(-123.654), NumericFromDouble(-123.456), LESS},
      {Numeric(-1), Numeric(-1), EQUAL},
      {Numeric(1), NullNumeric(), NULL_VALUE},

      // numeric vs. int64_t
      {Int64(0), NumericValue::MaxValue(), LESS},
      {NumericValue::MinValue(), int64min, LESS},
      {Int64(1), Numeric(1), EQUAL},
      {Int64(123), NumericFromDouble(123.654), LESS},
      {NumericFromDouble(-123.456), Int64(-123), LESS},
      {Int64(-1), Numeric(-1), EQUAL},
      {Int64(1), NullNumeric(), NULL_VALUE},

      // numeric vs. uint64_t
      {Uint64(0), NumericValue::MaxValue(), LESS},
      {NumericValue::MinValue(), uint64max, LESS},
      {Uint64(1), Numeric(1), EQUAL},
      {Uint64(123), NumericFromDouble(123.654), LESS},
      {NumericFromDouble(-123.456), Uint64(123), LESS},
      {Numeric(-1), Uint64(1), LESS},
      {Uint64(1), NullNumeric(), NULL_VALUE},

      // numeric vs. double
      {Double(0), NumericValue::MaxValue(), LESS},
      {doublemin, NumericValue::MinValue(), LESS},
      {double_neg_inf, NumericValue::MinValue(), LESS},
      {NumericValue::MaxValue(), double_pos_inf, LESS},
      {NumericValue::MaxValue(), double_nan, UNORDERED},
      {Double(1.0), Numeric(1), EQUAL},
      {Double(0.0), Numeric(0), EQUAL},
      {Double(-0.0), Numeric(0), EQUAL},
      {Double(123), NumericFromDouble(123.654), LESS},
      {NumericFromDouble(-123.456), Double(-123), LESS},
      {Double(-123.456), NumericFromDouble(-123.456), EQUAL},
      {Double(-1), Numeric(-1), EQUAL},
      {Double(1), NullNumeric(), NULL_VALUE},

      // bignumeric
      {BigNumeric(0), BigNumeric(BigNumericValue::MaxValue()), LESS},
      {BigNumeric(BigNumericValue::MinValue()), BigNumeric(0), LESS},
      {BigNumeric(1), BigNumeric(1), EQUAL},
      {BigNumeric(BigNumericValue::FromStringStrict("123.456").ValueOrDie()),
       BigNumeric(BigNumericValue::FromStringStrict("123.654").ValueOrDie()),
       LESS},
      {BigNumeric(BigNumericValue::FromStringStrict("-123.654").ValueOrDie()),
       BigNumeric(BigNumericValue::FromStringStrict("-123.456").ValueOrDie()),
       LESS},
      {BigNumeric(-1), BigNumeric(-1), EQUAL},
      {BigNumeric(1), NullBigNumeric(), NULL_VALUE},

      // bignumeric vs. int64_t
      {Int64(0), BigNumeric(BigNumericValue::MaxValue()), LESS},
      {BigNumeric(BigNumericValue::MinValue()), int64min, LESS},
      {Int64(1), BigNumeric(1), EQUAL},
      {Int64(123),
       BigNumeric(BigNumericValue::FromStringStrict("123.654").ValueOrDie()),
       LESS},
      {BigNumeric(BigNumericValue::FromStringStrict("-123.456").ValueOrDie()),
       Int64(-123), LESS},
      {Int64(-1), BigNumeric(-1), EQUAL},
      {Int64(1), NullBigNumeric(), NULL_VALUE},

      // bignumeric vs. uint64_t
      {Uint64(0), BigNumeric(BigNumericValue::MaxValue()), LESS},
      {BigNumeric(BigNumericValue::MinValue()), uint64max, LESS},
      {Uint64(1), BigNumeric(1), EQUAL},
      {Uint64(123),
       BigNumeric(BigNumericValue::FromStringStrict("123.654").ValueOrDie()),
       LESS},
      {BigNumeric(BigNumericValue::FromStringStrict("-123.456").ValueOrDie()),
       Uint64(123), LESS},
      {BigNumeric(-1), Uint64(1), LESS},
      {Uint64(1), NullBigNumeric(), NULL_VALUE},

      // bignumeric vs. floating point
      {Double(0), BigNumeric(BigNumericValue::MaxValue()), LESS},
      {doublemin, BigNumeric(BigNumericValue::MinValue()), LESS},
      {double_neg_inf, BigNumeric(BigNumericValue::MinValue()), LESS},
      {BigNumeric(BigNumericValue::MaxValue()), double_pos_inf, LESS},
      {BigNumeric(BigNumericValue::MaxValue()), float_pos_inf, LESS},
      {BigNumeric(BigNumericValue::MaxValue()), double_nan, UNORDERED},
      {Double(1.0), BigNumeric(1), EQUAL},
      {Double(0.0), BigNumeric(0), EQUAL},
      {Double(-0.0), BigNumeric(0), EQUAL},
      {Double(123),
       BigNumeric(BigNumericValue::FromStringStrict("123.654").ValueOrDie()),
       LESS},
      {BigNumeric(BigNumericValue::FromStringStrict("-123.456").ValueOrDie()),
       Double(-123), LESS},
      {Double(-123.456),
       BigNumeric(BigNumericValue::FromStringStrict("-123.456").ValueOrDie()),
       EQUAL},
      {Double(-1), BigNumeric(-1), EQUAL},
      {Double(1), NullBigNumeric(), NULL_VALUE},

      // bignumeric vs numeric
      {Numeric(0), BigNumeric(BigNumericValue::MaxValue()), LESS},
      {BigNumeric(BigNumericValue::MinValue()), Numeric(0), LESS},
      {Numeric(1), BigNumeric(1), EQUAL},
      {Numeric(NumericValue::FromStringStrict("123.456").ValueOrDie()),
       BigNumeric(BigNumericValue::FromStringStrict("123.654").ValueOrDie()),
       LESS},
      {Numeric(NumericValue::FromStringStrict("-123.654").ValueOrDie()),
       BigNumeric(BigNumericValue::FromStringStrict("-123.456").ValueOrDie()),
       LESS},
      {Numeric(-1), BigNumeric(-1), EQUAL},
      {Numeric(1), NullBigNumeric(), NULL_VALUE},
      {BigNumeric(1), NullNumeric(), NULL_VALUE},

      // string
      {"hello", "hello", EQUAL},
      {"bye", "hello", LESS},
      {"@", "A", LESS},
      {"a", "aa", LESS},
      {"Case sensitive", "case sensitive", LESS},
      {"hello world", NullString(), NULL_VALUE},
      // Cyrillic UTF-8 characters
      {"ъ", "ь", LESS},
      {"", NullString(), NULL_VALUE},

      // bytes
      {Bytes("hello"), Bytes("hello"), EQUAL},
      {Bytes("bye"), Bytes("hello"), LESS},
      {Bytes("@"), Bytes("A"), LESS},
      {Bytes("a"), Bytes("aa"), LESS},
      {Bytes("Case sensitive"), Bytes("case sensitive"), LESS},
      {Bytes("hello world"), NullBytes(), NULL_VALUE},
      // Cyrillic UTF-8 characters
      {Bytes("ъ"), Bytes("ь"), LESS},
      {Bytes(""), NullBytes(), NULL_VALUE},

      // date
      {Date(1), Date(1), EQUAL},
      {Date(-1), Date(0), LESS},
      {Date(-10), Date(-1), LESS},
      {Date(1), Date(10), LESS},
      {Date(1), NullDate(), NULL_VALUE},

      // timestamp
      {Timestamp(1), Timestamp(1), EQUAL},
      {Timestamp(-1), Timestamp(0), LESS},
      {Timestamp(-10), Timestamp(-1), LESS},
      {Timestamp(1), Timestamp(10), LESS},
      {Timestamp(1), NullTimestamp(), NULL_VALUE},

      // enum
      {enum0, enum0, EQUAL},
      {enum1, enum1, EQUAL},
      {enum0, enum1, LESS},
      {enum0, Null(TestEnumType()), NULL_VALUE},

      // time
      // micros
      {TimeMicros(1, 2, 3, 4), TimeMicros(1, 2, 3, 4), EQUAL},
      {TimeMicros(1, 2, 3, 4), TimeMicros(1, 2, 3, 5), LESS},
      {TimeMicros(1, 2, 3, 4), TimeMicros(1, 2, 5, 4), LESS},
      {TimeMicros(1, 2, 3, 4), TimeMicros(1, 5, 3, 4), LESS},
      {TimeMicros(1, 2, 3, 4), TimeMicros(5, 2, 3, 4), LESS},
      {TimeMicros(1, 2, 3, 4), NullTime(), NULL_VALUE},

      // datetime
      // micros
      {DatetimeMicros(2006, 1, 2, 3, 4, 5, 654321),
       DatetimeMicros(2006, 1, 2, 3, 4, 5, 654321), EQUAL},
      {DatetimeMicros(2006, 1, 2, 3, 4, 5, 654321),
       DatetimeMicros(2006, 1, 2, 3, 4, 5, 765432), LESS},
      {DatetimeMicros(2006, 1, 2, 3, 4, 5, 654321),
       DatetimeMicros(2006, 1, 2, 3, 4, 7, 654321), LESS},
      {DatetimeMicros(2006, 1, 2, 3, 4, 5, 654321),
       DatetimeMicros(2006, 1, 2, 3, 7, 5, 654321), LESS},
      {DatetimeMicros(2006, 1, 2, 3, 4, 5, 654321),
       DatetimeMicros(2006, 1, 2, 7, 4, 5, 654321), LESS},
      {DatetimeMicros(2006, 1, 2, 3, 4, 5, 654321),
       DatetimeMicros(2006, 1, 7, 3, 4, 5, 654321), LESS},
      {DatetimeMicros(2006, 1, 2, 3, 4, 5, 654321),
       DatetimeMicros(2006, 7, 2, 3, 4, 5, 654321), LESS},
      {DatetimeMicros(2006, 1, 2, 3, 4, 5, 654321),
       DatetimeMicros(2007, 1, 2, 3, 4, 5, 654321), LESS},
      {DatetimeMicros(2006, 1, 2, 3, 4, 5, 654321), NullDatetime(), NULL_VALUE},
  };
  if (include_nano_timestamp) {
    std::vector<ComparisonTest> nano_tests = {
        // time nanos
        {TimeNanos(1, 2, 3, 1234567), TimeNanos(1, 2, 3, 1234567), EQUAL},
        {TimeNanos(1, 2, 3, 1234567), TimeNanos(1, 2, 3, 1234568), LESS},
        {TimeNanos(1, 2, 3, 1234567), TimeNanos(1, 2, 5, 1234567), LESS},
        {TimeNanos(1, 2, 3, 1234567), TimeNanos(1, 5, 3, 1234567), LESS},
        {TimeNanos(1, 2, 3, 1234567), TimeNanos(5, 2, 3, 1234567), LESS},
        {TimeNanos(1, 2, 3, 1234567), NullTime(), NULL_VALUE},

        // datetime nanos
        {DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654321),
         DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654321), EQUAL},
        {DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654321),
         DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654322), LESS},
        {DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654321),
         DatetimeNanos(2006, 1, 2, 3, 4, 7, 987654321), LESS},
        {DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654321),
         DatetimeNanos(2006, 1, 2, 3, 7, 5, 987654321), LESS},
        {DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654321),
         DatetimeNanos(2006, 1, 2, 7, 4, 5, 987654321), LESS},
        {DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654321),
         DatetimeNanos(2006, 1, 7, 3, 4, 5, 987654321), LESS},
        {DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654321),
         DatetimeNanos(2006, 7, 2, 3, 4, 5, 987654321), LESS},
        {DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654321),
         DatetimeNanos(2007, 1, 2, 3, 4, 5, 987654321), LESS},
        {DatetimeNanos(2006, 1, 2, 3, 4, 5, 987654321), NullDatetime(),
         NULL_VALUE},
    };
    v.insert(v.end(), nano_tests.begin(), nano_tests.end());
  }
  if (include_struct_comparisons) {
    std::vector<ComparisonTest> struct_equality_tests =
        GetStructComparisonTests();
    v.insert(v.end(), struct_equality_tests.begin(),
             struct_equality_tests.end());
  }
  if (include_array_comparisons) {
    // Add a few more tests for array-specific comparison behaviors.
    std::vector<ComparisonTest> array_comparison_tests =
        GetArrayComparisonTests();

    // Duplicate tests by nesting the values into arrays, and do the same
    // comparison on the arrays.
    for (const ComparisonTest& test : v) {
      const ArrayType* left_array_type;
      ZETASQL_CHECK_OK(type_factory()->MakeArrayType(test.left.type(),
                                             &left_array_type));
      const Value left_array = values::Array(left_array_type, {test.left});

      const ArrayType* right_array_type;
      ZETASQL_CHECK_OK(type_factory()->MakeArrayType(test.right.type(),
                                             &right_array_type));
      const Value right_array = values::Array(right_array_type, {test.right});

      // We can only compare arrays if they are the same type.  We do not
      // do implicit coercion of arrays.  So if the types of the arguments
      // are not the same then skip this test.
      if (!left_array_type->Equals(right_array_type)) {
        continue;
      }

      array_comparison_tests.push_back(
          ComparisonTest(left_array, right_array, test.result));
    }
    v.insert(v.end(), array_comparison_tests.begin(),
             array_comparison_tests.end());
  }
  return v;
}

// Builds a QueryParamsWithResult from <input> and <out>, and appends it
// to <result>.  Wraps <out> with a feature set-result map if needed, in
// the following cases:
//
// 1) If there is any TIME/DATETIME typed value in the input, then
//    FEATURE_V_1_2_CIVIL_TIME is added to the feature set.
// 2) If <array_language_feature> is present then it is added.
// 3) If the <input> includes the NUMERIC type, then FEATURE_NUMERIC_TYPE
//    is added.
//
// If none of these are true, then constructs the QueryParamsWithResult
// directly from  <input>/<out>.
static void AddTestWithPossiblyWrappedResultWithRequiredFeatures(
    const std::vector<ValueConstructor>& input, const Value& out,
    const absl::optional<LanguageFeature>& array_language_feature,
    std::vector<QueryParamsWithResult>* result) {
  bool has_any_civil_time = false;
  bool has_any_numeric = false;
  bool has_any_bignumeric = false;
  bool has_any_array = false;
  // Check the inputs for civil time, numeric, and arrays.
  for (const auto& each : input) {
    if (each.type()->UsingFeatureV12CivilTimeType()) {
      has_any_civil_time = true;
    }
    if (each.type()->IsNumericType()) {
      has_any_numeric = true;
    }
    if (each.type()->IsBigNumericType()) {
      has_any_bignumeric = true;
    }
    if (each.type()->IsArray()) {
      has_any_array = true;
      if (each.type()->AsArray()->element_type()->IsNumericType()) {
        has_any_numeric = true;
      }
      if (each.type()->AsArray()->element_type()->IsBigNumericType()) {
        has_any_bignumeric = true;
      }
    }
  }
  // Check the output as well.
  if (out.type()->UsingFeatureV12CivilTimeType()) {
    has_any_civil_time = true;
  }
  if (out.type()->IsNumericType()) {
    has_any_numeric = true;
  }
  if (out.type()->IsBigNumericType()) {
    has_any_bignumeric = true;
  }
  if (out.type()->IsArray()) {
    has_any_array = true;
    if (out.type()->AsArray()->element_type()->IsNumericType()) {
      has_any_numeric = true;
    }
    if (out.type()->AsArray()->element_type()->IsBigNumericType()) {
      has_any_bignumeric = true;
    }
  }

  // Build the feature set.
  QueryParamsWithResult::FeatureSet feature_set;
  if (has_any_civil_time) {
    feature_set.insert(FEATURE_V_1_2_CIVIL_TIME);
  }
  if (has_any_numeric) {
    feature_set.insert(FEATURE_NUMERIC_TYPE);
  }
  if (has_any_array && array_language_feature) {
    feature_set.insert(*array_language_feature);
  }
  if (has_any_bignumeric) {
    feature_set.insert(FEATURE_BIGNUMERIC_TYPE);
  }

  // If the feature set is not empty then wrap the output result in
  // a feature set map.
  if (!feature_set.empty()) {
    result->push_back(QueryParamsWithResult(
        input, {{feature_set, QueryParamsWithResult::Result(out)}}));
  } else {
    result->push_back(QueryParamsWithResult(input, out));
  }
}

// Wraps any test cases that use NUMERIC with FEATURE_NUMERIC_TYPE.
static void WrapNumericTestCases(std::vector<QueryParamsWithResult>* tests) {
  for (auto& test_case : *tests) {
    if (test_case.HasEmptyFeatureSetAndNothingElse() &&
        test_case.result().type()->IsNumericType()) {
      test_case = test_case.WrapWithFeature(FEATURE_NUMERIC_TYPE);
    }
  }
}

// Wraps any test cases that use BIGNUMERIC with FEATURE_BIGNUMERIC_TYPE.
static void WrapBigNumericTestCases(std::vector<QueryParamsWithResult>* tests) {
  for (auto& test_case : *tests) {
    if (test_case.HasEmptyFeatureSetAndNothingElse() &&
        test_case.result().type()->IsBigNumericType()) {
      test_case = test_case.WrapWithFeature(FEATURE_BIGNUMERIC_TYPE);
    }
  }
}

std::vector<QueryParamsWithResult> GetFunctionTestsEqual(
    bool include_nano_timestamp) {
  std::vector<QueryParamsWithResult> result;
  for (const ComparisonTest& test : GetComparisonTests(
           /*include_struct_comparisons=*/true,
           /*include_array_comparisons=*/true, include_nano_timestamp)) {
    Value out;
    switch (test.result) {
      case NULL_VALUE:
        out = NullBool();
        break;
      case EQUAL:
        out = True();
        break;
      case LESS:
      case UNEQUAL:
      case UNORDERED:
        out = False();
        break;
    }
    AddTestWithPossiblyWrappedResultWithRequiredFeatures(
        {test.left, test.right}, out,
        /*array_language_feature=*/FEATURE_V_1_1_ARRAY_EQUALITY, &result);
    AddTestWithPossiblyWrappedResultWithRequiredFeatures(
        {test.right, test.left}, out,
        /*array_language_feature=*/FEATURE_V_1_1_ARRAY_EQUALITY, &result);
  }
  return result;
}

std::vector<QueryParamsWithResult> GetFunctionTestsNotEqual(
    bool include_nano_timestamp) {
  std::vector<QueryParamsWithResult> result;
  for (const ComparisonTest& test : GetComparisonTests(
           /*include_struct_comparisons=*/true,
           /*include_array_comparisons=*/true, include_nano_timestamp)) {
    Value out;
    switch (test.result) {
      case NULL_VALUE:
        out = NullBool();
        break;
      case LESS:
      case UNEQUAL:
      case UNORDERED:
        out = True();
        break;
      case EQUAL:
        out = False();
        break;
    }
    AddTestWithPossiblyWrappedResultWithRequiredFeatures(
        {test.left, test.right}, out,
        /*array_language_feature=*/FEATURE_V_1_1_ARRAY_EQUALITY, &result);
    AddTestWithPossiblyWrappedResultWithRequiredFeatures(
        {test.right, test.left}, out,
        /*array_language_feature=*/FEATURE_V_1_1_ARRAY_EQUALITY, &result);
  }
  return result;
}

std::vector<QueryParamsWithResult> GetFunctionTestsGreater(
    bool include_nano_timestamp) {
  std::vector<QueryParamsWithResult> result;
  for (const ComparisonTest& test : GetComparisonTests(
           /*include_struct_comparisons=*/false,
           /*include_array_comparisons=*/true, include_nano_timestamp)) {
    Value out;
    switch (test.result) {
      case NULL_VALUE:
        out = NullBool();
        break;
      case LESS:
      case EQUAL:
      case UNORDERED:
        out = False();
        break;
      case UNEQUAL:
        out = NullBool();
        break;
    }
    AddTestWithPossiblyWrappedResultWithRequiredFeatures(
        {test.left, test.right}, out,
        /*array_language_feature=*/FEATURE_V_1_3_ARRAY_ORDERING, &result);
    AddTestWithPossiblyWrappedResultWithRequiredFeatures(
        {test.right, test.left}, (test.result == LESS) ? True() : out,
        /*array_language_feature=*/FEATURE_V_1_3_ARRAY_ORDERING, &result);
  }
  return result;
}

std::vector<QueryParamsWithResult> GetFunctionTestsGreaterOrEqual(
    bool include_nano_timestamp) {
  std::vector<QueryParamsWithResult> result;
  for (const ComparisonTest& test : GetComparisonTests(
           /*include_struct_comparisons=*/false,
           /*include_array_comparisons=*/true, include_nano_timestamp)) {
    Value out;
    switch (test.result) {
      case NULL_VALUE:
        out = NullBool();
        break;
      case EQUAL:
        out = True();
        break;
      case LESS:
      case UNORDERED:
        out = False();
        break;
      case UNEQUAL:
        out = NullBool();
        break;
    }
    AddTestWithPossiblyWrappedResultWithRequiredFeatures(
        {test.left, test.right}, out,
        /*array_language_feature=*/FEATURE_V_1_3_ARRAY_ORDERING, &result);
    AddTestWithPossiblyWrappedResultWithRequiredFeatures(
        {test.right, test.left}, (test.result == LESS) ? True() : out,
        /*array_language_feature=*/FEATURE_V_1_3_ARRAY_ORDERING, &result);
  }
  return result;
}

std::vector<QueryParamsWithResult> GetFunctionTestsLess(
    bool include_nano_timestamp) {
  std::vector<QueryParamsWithResult> result;
  for (const ComparisonTest& test : GetComparisonTests(
           /*include_struct_comparisons=*/false,
           /*include_array_comparisons=*/true, include_nano_timestamp)) {
    Value out;
    switch (test.result) {
      case NULL_VALUE:
        out = NullBool();
        break;
      case LESS:
        out = True();
        break;
      case EQUAL:
      case UNORDERED:
        out = False();
        break;
      case UNEQUAL:
        out = NullBool();
        break;
    }
    AddTestWithPossiblyWrappedResultWithRequiredFeatures(
        {test.left, test.right}, out,
        /*array_language_feature=*/FEATURE_V_1_3_ARRAY_ORDERING, &result);
    AddTestWithPossiblyWrappedResultWithRequiredFeatures(
        {test.right, test.left}, (test.result == LESS) ? False() : out,
        /*array_language_feature=*/FEATURE_V_1_3_ARRAY_ORDERING, &result);
  }
  return result;
}

std::vector<QueryParamsWithResult> GetFunctionTestsLessOrEqual(
    bool include_nano_timestamp) {
  std::vector<QueryParamsWithResult> result;
  for (const ComparisonTest& test : GetComparisonTests(
           /*include_struct_comparisons=*/false,
           /*include_array_comparisons=*/true, include_nano_timestamp)) {
    Value out;
    switch (test.result) {
      case NULL_VALUE:
        out = NullBool();
        break;
      case EQUAL:
      case LESS:
        out = True();
        break;
      case UNORDERED:
        out = False();
        break;
      case UNEQUAL:
        out = NullBool();
        break;
    }
    AddTestWithPossiblyWrappedResultWithRequiredFeatures(
        {test.left, test.right}, out,
        /*array_language_feature=*/FEATURE_V_1_3_ARRAY_ORDERING, &result);
    AddTestWithPossiblyWrappedResultWithRequiredFeatures(
        {test.right, test.left}, (test.result == LESS) ? False() : out,
        /*array_language_feature=*/FEATURE_V_1_3_ARRAY_ORDERING, &result);
  }
  return result;
}

std::vector<QueryParamsWithResult> GetFunctionTestsInWithoutNulls() {
  std::vector<std::array<Value, 3>> type_sets = {
      {{String("a"), String("foo"), String("3523523zz5")}},
      {{Int32(4), Int32(-1), Int32(6)}},
      {{Int64(std::numeric_limits<int64_t>::lowest()), Int64(-1),
        Int64(std::numeric_limits<int64_t>::max())}},
      {{Float(std::numeric_limits<float>::lowest()),
        Float(std::numeric_limits<float>::max()),
        Float(std::numeric_limits<float>::min())}},
      {{Float(0.0f), Float(INFINITY), Float(-INFINITY)}},
      {{Double(0.0f), Double(INFINITY), Double(-INFINITY)}},
      {{Float(4.0f), Float(2.0), Float(8.0)}},
      {{Double(4.0f), Double(2.0), Double(8.0)}},
      {{Double(std::numeric_limits<double>::lowest()),
        Double(std::numeric_limits<double>::max()),
        Double(std::numeric_limits<double>::min())}},
  };
  std::vector<QueryParamsWithResult> ret;
  Value null_bool = NullBool();
  for (const auto& type_set : type_sets) {
    const Value& a = type_set[0];
    const Value& b = type_set[1];
    const Value& c = type_set[2];
    Value null = Value::Null(a.type());
    ret.insert(
        ret.end(),
        {
            // True.
            {{a, a}, true},
            {{a, a, b}, true},
            {{a, b, a}, true},
            {{b, a, b, c}, true},
            {{c, a, c}, true},
            {{b, b, c, a}, true},
            {{b, b, b, a, a}, true},
            {{b, b, b, b}, true},
            // False.
            {{a, b}, false},
            {{b, a, c}, false},
            {{b, a, a, c, c}, false},
            {{c, a, b, b}, false},
            // NULL first.
            {{null, a}, null_bool},
            {{null, a, b}, null_bool},
            {{null, a, b, c}, null_bool},
            {{null, b, b, a, a}, null_bool},
            {{null, b, b, b}, null_bool},
        });
  }

  auto nanf = Float(std::nanf(""));
  auto nan = Double(std::nan(""));
  ret.insert(ret.end(),
             {
                 // 0.0 == -0.0
                 {{Float(0.0f), Float(-0.0f)}, true},
                 {{Float(0.0f), Float(-0.0f), Float(3.14f)}, true},
                 {{Float(0.0f), Float(1.0f), Float(-0.0f), Float(3.14f)}, true},
                 {{Float(-0.0f), Float(0.0f)}, true},
                 {{Float(-0.0f), Float(0.0f), Float(3.14f)}, true},
                 {{Float(-0.0f), Float(1.0f), Float(0.0f), Float(3.14f)}, true},
                 {{Double(0.0), Double(-0.0)}, true},
                 {{Double(0.0), Double(-0.0), Double(3.14)}, true},
                 {{Double(0.0), Double(1), Double(-0.0), Double(3.14)}, true},
                 {{Double(-0.0), Double(0.0)}, true},
                 {{Double(-0.0), Double(0.0), Double(3.14)}, true},
                 {{Double(-0.0), Double(1), Double(0.0), Double(3.14)}, true},
                 // NaN != NaN
                 {{nanf, nanf}, false},
                 {{nanf, nanf, Float(3.14f)}, false},
                 {{nanf, Float(2.0f), nanf, Float(3.14f)}, false},
                 {{nan, nan}, false},
                 {{nan, nan, Double(3.14)}, false},
                 {{nan, Double(2), nan, Double(3.14)}, false},
                 // Bools.
                 {{true, true}, true},
                 {{false, false}, true},
                 {{true, false}, false},
                 {{false, true}, false},
                 {{true, true, false}, true},
                 {{false, true, false}, true},
                 {{null_bool, true}, null_bool},
             });
  return ret;
}

std::vector<QueryParamsWithResult> GetFunctionTestsInWithNulls() {
  std::vector<std::array<Value, 3>> type_sets = {
      {{String("a"), String("foo"), String("3523523zz5")}},
      {{Int32(4), Int32(-1), Int32(6)}},
      {{Int64(std::numeric_limits<int64_t>::lowest()), Int64(-1),
        Int64(std::numeric_limits<int64_t>::max())}},
      {{Float(std::numeric_limits<float>::lowest()),
        Float(std::numeric_limits<float>::max()),
        Float(std::numeric_limits<float>::min())}},
      {{Float(0.0f), Float(INFINITY), Float(-INFINITY)}},
      {{Double(0.0f), Double(INFINITY), Double(-INFINITY)}},
      {{Float(4.0f), Float(2.0), Float(8.0)}},
      {{Double(4.0f), Double(2.0), Double(8.0)}},
      {{Double(std::numeric_limits<double>::lowest()),
        Double(std::numeric_limits<double>::max()),
        Double(std::numeric_limits<double>::min())}},
  };
  std::vector<QueryParamsWithResult> ret;
  Value null_bool = NullBool();
  for (const auto& type_set : type_sets) {
    const Value& a = type_set[0];
    const Value& b = type_set[1];
    const Value& c = type_set[2];
    Value null = Value::Null(a.type());
    ret.insert(
        ret.end(),
        {
            // True with NULLs.
            {{a, a, null}, true},
            {{a, null, a}, true},
            {{a, a, null, null}, true},
            {{a, null, a}, true},
            {{a, null, null, a}, true},
            {{a, null, a, null}, true},
            {{a, null, null, a, null, null, a}, true},
            {{b, null, null, a, null, null, b}, true},
            {{b, null, null, a, null, null, b, null, b, null, a, null, null},
             true},
            // Not-True with NULLs.
            {{b, a, null}, null_bool},
            {{b, null, c}, null_bool},
            {{b, a, null, null}, null_bool},
            {{b, null, c}, null_bool},
            {{b, null, null, a}, null_bool},
            {{b, null, c, null}, null_bool},
            {{b, null, null, a, null, null, a}, null_bool},
            {{b, null, null, a, null, null, c}, null_bool},
            {{b, null, null, a, null, null, c, null, c, null, a, null, null},
             null_bool},
            // NULL first.
            {{null, b, null}, null_bool},
            {{null, null, c, null}, null_bool},
        });
  }

  ret.insert(ret.end(),
             {
                 {{true, true, null_bool}, true},
                 {{false, false, null_bool}, true},
                 {{true, false, null_bool}, null_bool},
                 {{false, true, null_bool}, null_bool},
                 {{true, true, false, null_bool}, true},
                 {{false, true, false, null_bool}, true},
             });
  return ret;
}

std::vector<QueryParamsWithResult> GetFunctionTestsIn() {
  std::vector<QueryParamsWithResult> ret = GetFunctionTestsInWithNulls();
  std::vector<QueryParamsWithResult> tests_without_nulls =
      GetFunctionTestsInWithoutNulls();
  ret.insert(ret.end(), tests_without_nulls.begin(), tests_without_nulls.end());
  return ret;
}

std::vector<QueryParamsWithResult> GetFunctionTestsStructIn() {
  const StructType* struct_type = SimpleStructType();  // a: string, b: int32_t
  const Value struct0 = Value::Struct(struct_type, {String("foo"), Int32(0)});
  const Value struct1 = Value::Struct(struct_type, {String("bar"), Int32(1)});
  const Value struct2 = Value::Struct(struct_type, {String("baz"), Int32(2)});
  const Value struct1_with_null1 =
      Value::Struct(struct_type, {NullString(), Int32(1)});
  const Value struct1_with_null2 =
      Value::Struct(struct_type, {String("bar"), NullInt32()});
  const Value struct_with_all_nulls =
      Value::Struct(struct_type, {NullString(), NullInt32()});
  const Value null_struct = Value::Null(struct_type);
  // These DCHECKs are only here to more clearly show the contents of
  // all the struct values.
  DCHECK_EQ("(\"foo\", 0)",    struct0.GetSQLLiteral());
  DCHECK_EQ("(\"bar\", 1)",    struct1.GetSQLLiteral());
  DCHECK_EQ("(\"baz\", 2)",    struct2.GetSQLLiteral());
  DCHECK_EQ("(NULL, 1)",       struct1_with_null1.GetSQLLiteral());
  DCHECK_EQ("(\"bar\", NULL)", struct1_with_null2.GetSQLLiteral());
  DCHECK_EQ("(NULL, NULL)",    struct_with_all_nulls.GetSQLLiteral());
  DCHECK_EQ("NULL",            null_struct.GetSQLLiteral());

  return {
    {{struct0, struct0}, True()},
    {{struct0, struct1}, False()},
    {{struct0, struct0, struct1, struct2}, True()},
    {{struct1, struct0, struct1, struct2}, True()},
    {{struct2, struct0, struct1, struct2}, True()},

    {{struct0, struct1, struct2}, False()},
    {{struct0, struct1_with_null1, struct0}, True()},
    {{struct0, struct1_with_null2, struct0}, True()},
    {{struct0, struct_with_all_nulls, struct0}, True()},
    {{struct0, null_struct, struct0}, True()},
    {{struct0, null_struct, struct0}, True()},
    {{struct0, struct1_with_null1}, False()},
    {{struct0, struct1_with_null2}, False()},
    {{struct0, struct_with_all_nulls}, NullBool()},
    {{struct0, null_struct}, NullBool()},

    {{struct1, struct1_with_null1, struct0}, NullBool()},
    {{struct1, struct1_with_null2, struct0}, NullBool()},
    {{struct0, struct_with_all_nulls}, NullBool()},
    {{struct1, struct_with_all_nulls}, NullBool()},
    {{struct2, struct_with_all_nulls}, NullBool()},

    {{struct1_with_null1, struct1_with_null1}, NullBool()},
    {{struct1_with_null1, struct0, struct1}, NullBool()},
    {{struct1_with_null2, struct1_with_null2}, NullBool()},
    {{struct1_with_null2, struct0, struct1}, NullBool()},
    {{struct1_with_null2, struct0}, False()},
    {{struct1_with_null2, struct0}, False()},

    {{struct_with_all_nulls, struct0}, NullBool()},
    {{struct_with_all_nulls, struct1}, NullBool()},
    {{struct_with_all_nulls, struct2}, NullBool()},
    {{struct_with_all_nulls, struct1_with_null1}, NullBool()},
    {{struct_with_all_nulls, struct1_with_null2}, NullBool()},
    {{struct_with_all_nulls, struct_with_all_nulls}, NullBool()},
    {{struct_with_all_nulls, null_struct}, NullBool()},

    {{null_struct, struct0}, NullBool()},
    {{null_struct, struct1}, NullBool()},
    {{null_struct, struct2}, NullBool()},
    {{null_struct, struct1_with_null1}, NullBool()},
    {{null_struct, struct1_with_null2}, NullBool()},
    {{null_struct, struct_with_all_nulls}, NullBool()},
    {{null_struct, null_struct}, NullBool()},
  };
}

std::vector<QueryParamsWithResult> GetFunctionTestsIsNull() {
  const ArrayType* struct_array_type = MakeArrayType(SimpleStructType());
  const ArrayType* nullable_int_array_type =
      MakeArrayType(NullableIntProtoType());
  std::vector<QueryParamsWithResult> v = {
      // Simple types.
      {{NullInt32()},                                           True()},
      {{NullInt64()},                                           True()},
      {{NullUint32()},                                          True()},
      {{NullUint64()},                                          True()},
      {{NullBool()},                                            True()},
      {{NullFloat()},                                           True()},
      {{NullDouble()},                                          True()},
      {{NullString()},                                          True()},
      {{NullBytes()},                                           True()},

      {{Int32(1)},                                              False()},
      {{Int64(1)},                                              False()},
      {{Uint32(1)},                                             False()},
      {{Uint64(1)},                                             False()},
      {{True()},                                                False()},
      {{False()},                                               False()},
      {{Float(1.1)},                                            False()},
      {{Double(1.1)},                                           False()},
      {{String("a")},                                           False()},
      {{Bytes("b")},                                            False()},

      // Date and timestamp types.
      {{NullDate()},                                            True()},
      {{NullTimestamp()},                                       True()},

      {{Date(0)},                                               False()},
      {{Timestamp(0)},                                          False()},

      // Enum types.
      {{Value::Null(TestEnumType())},                           True()},
      {{Value::Enum(TestEnumType(), 0)},                        False()},

      // Proto types.
      {{Value::Null(KitchenSinkProtoType())},                   True()},
      {{Value::Null(NullableIntProtoType())},                   True()},

      {{KitchenSink("int64_key_1: 1 int64_key_2: 2")},          False()},
      {{NullableInt("")},                                       False()},
      {{NullableInt("value: 1")},                               False()},

      // Struct types.
      {{Value::Null(SimpleStructType())},                       True()},
      {{Value::Null(AnotherStructType())},                      True()},

      {{Value::Struct(SimpleStructType(),
                      {String("a"), Int32(1)})},                False()},
      {{Value::Struct(SimpleStructType(),
                      {NullString(), NullInt32()})},            False()},

      // Array types.
      {{Value::Null(Int32ArrayType())},                         True()},
      {{Value::Null(Uint32ArrayType())},                        True()},
      {{Value::Null(BoolArrayType())},                          True()},
      {{Value::Null(DoubleArrayType())},                        True()},
      {{Value::Null(StringArrayType())},                        True()},
      {{Value::Null(BytesArrayType())},                         True()},
      {{Value::Null(struct_array_type)},                        True()},
      {{Value::Null(nullable_int_array_type)},                  True()},

      {{Value::Array(Int64ArrayType(), {}/* empty_array */)},   False()},
      {{Value::Array(Int64ArrayType(), {Int64(0), Int64(1)})},  False()},
      {{Value::Array(Int64ArrayType(),
                     {NullInt64(), NullInt64()})},              False()},
      {{Value::Array(StringArrayType(),
                     {String("a"), String("b")})},              False()},
      {{Value::Array(struct_array_type,
                     {Value::Struct(SimpleStructType(),
                                    {NullString(),
                                     NullInt32()})})},          False()},
      {{Value::Array(nullable_int_array_type,
                     {NullableInt("")})},                       False()},
  };
  return v;
}

std::vector<QueryParamsWithResult> GetFunctionTestsGreatest(
    bool include_nano_timestamp) {
  std::vector<QueryParamsWithResult> result;
  for (const ComparisonTest& test : GetComparisonTests(
           /*include_struct_comparisons=*/false,
           /*include_array_comparisons=*/false, include_nano_timestamp)) {
    // TODO: This should be 'Equivalent()', not 'Equals()'.  Need
    // to add tests that illustrate the difference.
    if (!test.left.type()->Equals(test.right.type())) {
      continue;  // Inputs to Greatest must all be of the same type.
    }
    Value out;
    switch (test.result) {
      case NULL_VALUE:
        out = Value::Null(test.left.type()); break;
      case LESS:
      case EQUAL:
        out = test.right; break;
      case UNORDERED:  // NaN
        out = test.GetNaN(); break;
      case UNEQUAL:
        // The UNEQUAL test result type is currently only used for ARRAY
        // comparisons, but GREATEST/LEAST do not support ARRAYS so this
        // is an unexpected condition.
        CHECK_NE(test.result, UNEQUAL)
            << "Unexpected comparison test result type:" << test.result;
    }
    // Binary
    AddTestWithPossiblyWrappedResultWithRequiredFeatures(
        {test.left, test.right}, out,
        /*array_language_feature=*/absl::optional<LanguageFeature>(), &result);
    // Ternary
    AddTestWithPossiblyWrappedResultWithRequiredFeatures(
        {test.right, test.left, test.right}, out,
        /*array_language_feature=*/absl::optional<LanguageFeature>(), &result);
  }
  return result;
}

std::vector<QueryParamsWithResult> GetFunctionTestsLeast(
    bool include_nano_timestamp) {
  std::vector<QueryParamsWithResult> result;
  for (const ComparisonTest& test : GetComparisonTests(
           /*include_struct_comparisons=*/false,
           /*include_array_comparisons=*/false, include_nano_timestamp)) {
    // TODO: This should be 'Equivalent()', not 'Equals()'.  Need
    // to add tests that illustrate the difference.
    if (!test.left.type()->Equals(test.right.type())) {
      continue;  // Inputs to Least must all be of the same type.
    }
    Value out;
    switch (test.result) {
      case NULL_VALUE:
        out = Value::Null(test.left.type()); break;
      case LESS:
      case EQUAL:
        out = test.left; break;
      case UNORDERED:  // NaN
        out = test.GetNaN(); break;
      case UNEQUAL:
        // The UNEQUAL test result type is currently only used for ARRAY
        // comparisons, but GREATEST/LEAST do not support ARRAYS so this
        // is an unexpected condition.
        CHECK_NE(test.result, UNEQUAL)
            << "Unexpected comparison test result type:" << test.result;
    }
    // Binary
    AddTestWithPossiblyWrappedResultWithRequiredFeatures(
        {test.left, test.right}, out,
        /*array_language_feature=*/absl::optional<LanguageFeature>(), &result);
    // Ternary
    AddTestWithPossiblyWrappedResultWithRequiredFeatures(
        {test.right, test.left, test.right}, out,
        /*array_language_feature=*/absl::optional<LanguageFeature>(), &result);
  }
  return result;
}

// FromType is in {float, double}. ToType is in {int32_t, uint32_t, int64_t, uint64_t}.
template <typename FromType, typename ToType>
static std::vector<QueryParamsWithResult> TestCastPositiveRounding() {
  return {
    {{Value::Make<FromType>(1.1)}, Value::Make<ToType>(1)},
    {{Value::Make<FromType>(1.5)}, Value::Make<ToType>(2)},
    {{Value::Make<FromType>(1.9)}, Value::Make<ToType>(2)},
    {{Value::Make<FromType>(2.5)}, Value::Make<ToType>(3)},
  };
}

// FromType = {float, double}. ToType = {int32_t, int64_t}.
template <typename FromType, typename ToType>
static std::vector<QueryParamsWithResult> TestCastNegativeRounding() {
  return {
    {{Value::Make<FromType>(-1.1)}, Value::Make<ToType>(-1)},
    {{Value::Make<FromType>(-1.5)}, Value::Make<ToType>(-2)},
    {{Value::Make<FromType>(-1.9)}, Value::Make<ToType>(-2)},
    {{Value::Make<FromType>(-2.5)}, Value::Make<ToType>(-3)},
  };
}

// FromType is in {float, double}. ToType is in {int32_t, uint32_t, int64_t, uint64_t,
// bool}.
template <typename FromType, typename ToType>
static std::vector<QueryParamsWithResult> TestCastInfinityError() {
  return {
      {{Value::Make<FromType>(std::numeric_limits<FromType>::quiet_NaN())},
       Value::MakeNull<ToType>(),
       OUT_OF_RANGE},
      {{Value::Make<FromType>(std::numeric_limits<FromType>::infinity())},
       Value::MakeNull<ToType>(),
       OUT_OF_RANGE},
      {{Value::Make<FromType>(-std::numeric_limits<FromType>::infinity())},
       Value::MakeNull<ToType>(),
       OUT_OF_RANGE},
  };
}

// FromType = {int32_t, int64_t, uint32_t, uint64_t, float, double}.
template <typename FromType>
static std::vector<QueryParamsWithResult> TestCastNumericNull() {
  const Value& from_null = Value::MakeNull<FromType>();
  return {
    {{from_null}, NullInt32()},
    {{from_null}, NullInt64()},
    {{from_null}, NullUint32()},
    {{from_null}, NullUint64()},
    {{from_null}, NullFloat()},
    {{from_null}, NullDouble()},
  };
}

std::vector<QueryParamsWithResult> GetFunctionTestsBitwiseNot() {
  return {
    {{NullInt32()}, NullInt32()},
    {{NullInt64()}, NullInt64()},
    {{NullUint32()}, NullUint32()},
    {{NullUint64()}, NullUint64()},
    {{NullBytes()}, NullBytes()},

    {{Int32(-1)}, Int32(0) },
    {{Int32(0)}, Int32(-1) },
    {{Int32(-2)}, Int32(1) },
    {{Int32(1)}, Int32(-2) },
    {{Int32(0xAAAAAAAA)}, Int32(0x55555555) },
    {{Int32(0x55555555)}, Int32(0xAAAAAAAA) },

    {{Int64(-1)}, Int64(0) },
    {{Int64(0)}, Int64(-1) },
    {{Int64(-2)}, Int64(1) },
    {{Int64(1)}, Int64(-2) },
    {{Int64(0xAAAAAAAAAAAAAAAA)}, Int64(0x5555555555555555) },
    {{Int64(0x5555555555555555)}, Int64(0xAAAAAAAAAAAAAAAA) },

    {{Uint32(0xFFFFFFFF)}, Uint32(0) },
    {{Uint32(0)}, Uint32(0xFFFFFFFF) },
    {{Uint32(0xAAAAAAAA)}, Uint32(0x55555555) },
    {{Uint32(0x55555555)}, Uint32(0xAAAAAAAA) },

    {{Uint64(0xFFFFFFFFFFFFFFFF)}, Uint64(0) },
    {{Uint64(0)}, Uint64(0xFFFFFFFFFFFFFFFF) },
    {{Uint64(0xAAAAAAAAAAAAAAAA)}, Uint64(0x5555555555555555) },
    {{Uint64(0x5555555555555555)}, Uint64(0xAAAAAAAAAAAAAAAA) },

    {{Bytes("")}, Bytes("") },
    {{Bytes("\0")}, Bytes("\xFF") },
    {{Bytes("\xFF")}, Bytes("\0") },
    {{Bytes("\x01\x23\x45\x67\x89\xAB\xCD\xEF\x55\xAA")},
        Bytes("\xFE\xDC\xBA\x98\x76\x54\x32\x10\xAA\x55") },
    {{Bytes("\xFE\xDC\xBA\x98\x76\x54\x32\x10\xAA\x55")},
        Bytes("\x01\x23\x45\x67\x89\xAB\xCD\xEF\x55\xAA") },
  };
}

std::vector<QueryParamsWithResult> GetFunctionTestsBitwiseOr() {
  return {
    {{NullInt32(), Int32(0)}, NullInt32()},
    {{Int32(1), NullInt32()}, NullInt32()},
    {{NullInt64(), Int64(2)}, NullInt64()},
    {{Int64(3), NullInt64()}, NullInt64()},
    {{NullUint32(), Uint32(4)}, NullUint32()},
    {{Uint32(5), NullUint32()}, NullUint32()},
    {{NullUint64(), Uint64(6)}, NullUint64()},
    {{Uint64(7), NullUint64()}, NullUint64()},
    {{NullBytes(), Bytes("foo")}, NullBytes()},
    {{Bytes("foo"), NullBytes()}, NullBytes()},

    {{Int32(0), Int32(0)}, Int32(0)},
    {{Int32(-1), Int32(0)}, Int32(-1)},
    {{Int32(0xAAAAAAAA), Int32(0x55555555)}, Int32(-1)},
    {{Int32(0), Int32(1)}, Int32(1)},
    {{Int32(2), Int32(1)}, Int32(3)},
    {{Int32(0xFF), Int32(1)}, Int32(0xFF)},

    {{Int64(0), Int64(0)}, Int64(0)},
    {{Int64(-1), Int64(0)}, Int64(-1)},
    {{Int64(0xAAAAAAAAAAAAAAAA), Int64(0x5555555555555555)}, Int64(-1)},
    {{Int64(0), Int64(1)}, Int64(1)},
    {{Int64(2), Int64(1)}, Int64(3)},
    {{Int64(0xFF), Int64(1)}, Int64(0xFF)},

    {{Uint32(0), Uint32(0)}, Uint32(0)},
    {{Uint32(0xFFFFFFFFU), Uint32(0)}, Uint32(0xFFFFFFFFU)},
    {{Uint32(0xAAAAAAAA), Uint32(0x55555555)}, Uint32(0xFFFFFFFFU)},
    {{Uint32(0), Uint32(1)}, Uint32(1)},
    {{Uint32(2), Uint32(1)}, Uint32(3)},
    {{Uint32(0xFF), Uint32(1)}, Uint32(0xFF)},

    {{Uint64(0), Uint64(0)}, Uint64(0)},
    {{Uint64(0xFFFFFFFFFFFFFFFFU), Uint64(0)}, Uint64(0xFFFFFFFFFFFFFFFFU)},
    {{Uint64(0xAAAAAAAAAAAAAAAA), Uint64(0x5555555555555555)},
        Uint64(0xFFFFFFFFFFFFFFFFU)},
    {{Uint64(0), Uint64(1)}, Uint64(1)},
    {{Uint64(2), Uint64(1)}, Uint64(3)},
    {{Uint64(0xFF), Uint64(1)}, Uint64(0xFF)},

    {{Bytes(""), Bytes("")}, Bytes("") },
    {{Bytes("\0"), Bytes("\xFF")}, Bytes("\xFF") },
    {{Bytes("\0\xFF"), Bytes("\xFF\0")}, Bytes("\xFF\xFF") },
    {{Bytes("\xAA\xAA\xAA\xAA\xAA"), Bytes("\x55\x55\x55\x55\x55")},
        Bytes("\xFF\xFF\xFF\xFF\xFF") },
    {{Bytes("\x01\x23\x45\x67\x89\xAB\xCD\xEF\xFE\xDC\xBA"),
      Bytes("\x12\x34\x56\x78\x9A\xBC\xDE\xF0\x0F\xED\xCB")},
        Bytes("\x13\x37\x57\x7F\x9B\xBF\xDF\xFF\xFF\xFD\xFB") },
    {{Bytes(""), Bytes("\xFF")}, NullBytes(), OUT_OF_RANGE },
  };
}

std::vector<QueryParamsWithResult> GetFunctionTestsBitwiseXor() {
  return {
    {{NullInt32(), Int32(0)}, NullInt32()},
    {{Int32(1), NullInt32()}, NullInt32()},
    {{NullInt64(), Int64(2)}, NullInt64()},
    {{Int64(3), NullInt64()}, NullInt64()},
    {{NullUint32(), Uint32(4)}, NullUint32()},
    {{Uint32(5), NullUint32()}, NullUint32()},
    {{NullUint64(), Uint64(6)}, NullUint64()},
    {{Uint64(7), NullUint64()}, NullUint64()},
    {{NullBytes(), Bytes("foo")}, NullBytes()},
    {{Bytes("foo"), NullBytes()}, NullBytes()},

    {{Int32(0), Int32(0)}, Int32(0)},
    {{Int32(-1), Int32(0)}, Int32(-1)},
    {{Int32(-1), Int32(-1)}, Int32(0)},
    {{Int32(0xAAAAAAAA), Int32(0x55555555)}, Int32(-1)},
    {{Int32(0xAAAAAAAA), Int32(0xFFFFFFFF)}, Int32(0x55555555)},
    {{Int32(2), Int32(1)}, Int32(3)},

    {{Int64(0), Int64(0)}, Int64(0)},
    {{Int64(-1), Int64(0)}, Int64(-1)},
    {{Int64(-1), Int64(-1)}, Int64(0)},
    {{Int64(0xAAAAAAAAAAAAAAAA), Int64(0x5555555555555555)}, Int64(-1)},
    {{Int64(0xAAAAAAAAAAAAAAAA), Int64(0xFFFFFFFFFFFFFFFF)},
        Int64(0x5555555555555555)},
    {{Int64(2), Int64(1)}, Int64(3)},

    {{Uint32(0), Uint32(0)}, Uint32(0)},
    {{Uint32(0xFFFFFFFFU), Uint32(0)}, Uint32(0xFFFFFFFFU)},
    {{Uint32(0xFFFFFFFFU), Uint32(0xFFFFFFFFU)}, Uint32(0)},
    {{Uint32(0xAAAAAAAAU), Uint32(0x55555555U)}, Uint32(0xFFFFFFFFU)},
    {{Uint32(0xAAAAAAAAU), Uint32(0xFFFFFFFFU)}, Uint32(0x55555555U)},
    {{Uint32(2), Uint32(1)}, Uint32(3)},

    {{Uint64(0), Uint64(0)}, Uint64(0)},
    {{Uint64(0xFFFFFFFFFFFFFFFFU), Uint64(0)}, Uint64(0xFFFFFFFFFFFFFFFFU)},
    {{Uint64(0xFFFFFFFFFFFFFFFFU), Uint64(0xFFFFFFFFFFFFFFFFU)}, Uint64(0)},
    {{Uint64(0xAAAAAAAAAAAAAAAAU), Uint64(0x5555555555555555U)},
        Uint64(0xFFFFFFFFFFFFFFFFU)},
    {{Uint64(0xAAAAAAAAAAAAAAAAU), Uint64(0xFFFFFFFFFFFFFFFFU)},
        Uint64(0x5555555555555555U)},
    {{Uint64(2), Uint64(1)}, Uint64(3)},

    {{Bytes(""), Bytes("")}, Bytes("") },
    {{Bytes("\0"), Bytes("\xFF")}, Bytes("\xFF") },
    {{Bytes("\0\xFF"), Bytes("\xFF\0")}, Bytes("\xFF\xFF") },
    {{Bytes("\xAA\xAA\xAA\xAA\xAA"), Bytes("\x55\x55\x55\x55\x55")},
        Bytes("\xFF\xFF\xFF\xFF\xFF") },
    {{Bytes("\x01\x23\x45\x67\x89\xAB\xCD\xEF\xFE\xDC\xBA"),
      Bytes("\x12\x34\x56\x78\x9A\xBC\xDE\xF0\x0F\xED\xCB")},
        Bytes("\x13\x17\x13\x1F\x13\x17\x13\x1F\xF1\x31\x71") },
    {{Bytes(""), Bytes("\xFF")}, NullBytes(), OUT_OF_RANGE },
  };
}

std::vector<QueryParamsWithResult> GetFunctionTestsBitwiseAnd() {
  return {
    {{NullInt32(), Int32(0)}, NullInt32()},
    {{Int32(1), NullInt32()}, NullInt32()},
    {{NullInt64(), Int64(2)}, NullInt64()},
    {{Int64(3), NullInt64()}, NullInt64()},
    {{NullUint32(), Uint32(4)}, NullUint32()},
    {{Uint32(5), NullUint32()}, NullUint32()},
    {{NullUint64(), Uint64(6)}, NullUint64()},
    {{Uint64(7), NullUint64()}, NullUint64()},
    {{NullBytes(), Bytes("foo")}, NullBytes()},
    {{Bytes("foo"), NullBytes()}, NullBytes()},

    {{Int32(0), Int32(0)}, Int32(0)},
    {{Int32(-1), Int32(0)}, Int32(0)},
    {{Int32(0xAAAAAAAA), Int32(0x55555555)}, Int32(0)},
    {{Int32(0xAAAAAAAA), Int32(0xFFFFFFFF)}, Int32(0xAAAAAAAA)},
    {{Int32(0xAAAAAAAA), Int32(0xF0F0F0F0)}, Int32(0xA0A0A0A0)},

    {{Int64(0), Int64(0)}, Int64(0)},
    {{Int64(-1), Int64(0)}, Int64(0)},
    {{Int64(0xAAAAAAAAAAAAAAAA), Int64(0x5555555555555555)}, Int64(0)},
    {{Int64(0xAAAAAAAAAAAAAAAA), Int64(0xFFFFFFFFFFFFFFFF)},
        Int64(0xAAAAAAAAAAAAAAAA)},
    {{Int64(0xAAAAAAAAAAAAAAAA), Int64(0xF0F0F0F0F0F0F0F0)},
        Int64(0xA0A0A0A0A0A0A0A0)},

    {{Uint32(0), Uint32(0)}, Uint32(0)},
    {{Uint32(0xFFFFFFFFU), Uint32(0)}, Uint32(0)},
    {{Uint32(0xAAAAAAAAU), Uint32(0x55555555U)}, Uint32(0)},
    {{Uint32(0xAAAAAAAAU), Uint32(0xFFFFFFFFU)}, Uint32(0xAAAAAAAAU)},
    {{Uint32(0xAAAAAAAAU), Uint32(0xF0F0F0F0U)}, Uint32(0xA0A0A0A0U)},

    {{Uint64(0), Uint64(0)}, Uint64(0)},
    {{Uint64(0xFFFFFFFFFFFFFFFFU), Uint64(0)}, Uint64(0)},
    {{Uint64(0xAAAAAAAAAAAAAAAAU), Uint64(0x5555555555555555U)}, Uint64(0)},
    {{Uint64(0xAAAAAAAAAAAAAAAAU), Uint64(0xFFFFFFFFFFFFFFFFU)},
        Uint64(0xAAAAAAAAAAAAAAAAU)},
    {{Uint64(0xAAAAAAAAAAAAAAAAU), Uint64(0xF0F0F0F0F0F0F0F0U)},
        Uint64(0xA0A0A0A0A0A0A0A0U)},

    {{Bytes(""), Bytes("")}, Bytes("") },
    {{Bytes("\0"), Bytes("\xFF")}, Bytes("\0")},
    {{Bytes("\0\xFF"), Bytes("\xFF\0")}, Bytes("\0\0") },
    {{Bytes("\xAA\xAA\xAA\xAA\xAA"), Bytes("\x55\x55\x55\x55\x55")},
        Bytes("\0\0\0\0\0") },
    {{Bytes("\x01\x23\x45\x67\x89\xAB\xCD\xEF\xFE\xDC\xBA"),
      Bytes("\x12\x34\x56\x78\x9A\xBC\xDE\xF0\x0F\xED\xCB")},
        Bytes("\x00\x20\x44\x60\x88\xA8\xCC\xE0\x0E\xCC\x8A") },
    {{Bytes(""), Bytes("\xFF")}, NullBytes(), OUT_OF_RANGE },
  };
}

std::vector<QueryParamsWithResult> GetFunctionTestsBitwiseLeftShift() {
  return {
      {{NullInt32(), Int64(0)}, NullInt32()},
      {{NullInt64(), Int64(0)}, NullInt64()},
      {{NullUint32(), Int64(0)}, NullUint32()},
      {{NullUint64(), Int64(0)}, NullUint64()},
      {{NullBytes(), Int64(0)}, NullBytes()},
      {{Int32(0), NullInt64()}, NullInt32()},
      {{Int64(0), NullInt64()}, NullInt64()},
      {{Uint32(0), NullInt64()}, NullUint32()},
      {{Uint64(0), NullInt64()}, NullUint64()},
      {{Bytes("foo"), NullInt64()}, NullBytes()},

      {{Int32(-1), Int64(0)}, Int32(-1)},
      {{Int32(-1), Int64(32)}, Int32(0)},
      {{Int32(-1), Int64(1)}, Int32(-2)},
      {{Int32(0x5555), Int64(16)}, Int32(0x55550000)},
      {{Int32(0x5555), Int64(-1)}, NullInt32(), OUT_OF_RANGE},

      {{Int64(-1), Int64(0)}, Int64(-1)},
      {{Int64(-1), Int64(64)}, Int64(0)},
      {{Int64(-1), Int64(1)}, Int64(-2)},
      {{Int64(0x5555), Int64(48)}, Int64(0x5555000000000000)},
      {{Int64(0x5555), Int64(-1)}, NullInt64(), OUT_OF_RANGE},

      {{Uint32(0xFFFFFFFFU), Int64(0)}, Uint32(0xFFFFFFFFU)},
      {{Uint32(0xFFFFFFFFU), Int64(32)}, Uint32(0)},
      {{Uint32(0xFFFFFFFFU), Int64(1)}, Uint32(0xFFFFFFFEU)},
      {{Uint32(0x5555), Int64(16)}, Uint32(0x55550000U)},
      {{Uint32(0x5555), Int64(-1)}, NullUint32(), OUT_OF_RANGE},

      {{Uint64(0xFFFFFFFFFFFFFFFFU), Int64(0)}, Uint64(0xFFFFFFFFFFFFFFFFU)},
      {{Uint64(0xFFFFFFFFFFFFFFFFU), Int64(64)}, Uint64(0)},
      {{Uint64(0xFFFFFFFFFFFFFFFFU), Int64(1)}, Uint64(0xFFFFFFFFFFFFFFFEU)},
      {{Uint64(0x5555), Int64(48)}, Uint64(0x5555000000000000U)},
      {{Uint64(0x5555), Int64(-1)}, NullUint64(), OUT_OF_RANGE},

      {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(0)},
       Bytes("\xFE\xDC\xBA\x98\x76")},
      {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(40)},
       Bytes("\x00\x00\x00\x00\x00")},
      {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(41)},
       Bytes("\x00\x00\x00\x00\x00")},
      {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(1)},
       Bytes("\xFD\xB9\x75\x30\xEC")},
      {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(4)},
       Bytes("\xED\xCB\xA9\x87\x60")},
      {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(17)},
       Bytes("\x75\x30\xEC\x00\x00")},
      {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(24)},
       Bytes("\x98\x76\x00\x00\x00")},
      {{Bytes("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"), Int64(64)},
       Bytes("\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0")},
      {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(-1)}, NullBytes(), OUT_OF_RANGE},
      // Empty input.
      {{Bytes(""), Int64(0)}, Bytes("")},
      {{Bytes(""), Int64(10)}, Bytes("")},
  };
}

std::vector<QueryParamsWithResult> GetFunctionTestsBitwiseRightShift() {
  return {
      {{NullInt32(), Int64(0)}, NullInt32()},
      {{NullInt64(), Int64(2)}, NullInt64()},
      {{NullUint32(), Int64(4)}, NullUint32()},
      {{NullUint64(), Int64(6)}, NullUint64()},
      {{NullBytes(), Int64(0)}, NullBytes()},
      {{Int32(0), NullInt64()}, NullInt32()},
      {{Int64(0), NullInt64()}, NullInt64()},
      {{Uint32(0), NullInt64()}, NullUint32()},
      {{Uint64(0), NullInt64()}, NullUint64()},
      {{Bytes("foo"), NullInt64()}, NullBytes()},

      {{Int32(-1), Int64(0)}, Int32(-1)},
      {{Int32(-1), Int64(32)}, Int32(0)},
      {{Int32(-1), Int64(1)}, Int32(0x7FFFFFFF)},
      {{Int32(0x55550000), Int64(16)}, Int32(0x5555)},
      {{Int32(0x5555), Int64(-1)}, NullInt32(), OUT_OF_RANGE},

      {{Int64(-1), Int64(0)}, Int64(-1)},
      {{Int64(-1), Int64(64)}, Int64(0)},
      {{Int64(-1), Int64(1)}, Int64(0x7FFFFFFFFFFFFFFF)},
      {{Int64(0x5555000000000000), Int64(48)}, Int64(0x5555)},
      {{Int64(0x5555), Int64(-1)}, NullInt64(), OUT_OF_RANGE},

      {{Uint32(0xFFFFFFFFU), Int64(0)}, Uint32(0xFFFFFFFFU)},
      {{Uint32(0xFFFFFFFFU), Int64(32)}, Uint32(0)},
      {{Uint32(0xFFFFFFFFU), Int64(1)}, Uint32(0x7FFFFFFFU)},
      {{Uint32(0x55550000U), Int64(16)}, Uint32(0x5555)},
      {{Uint32(0x5555), Int64(-1)}, NullUint32(), OUT_OF_RANGE},

      {{Uint64(0xFFFFFFFFFFFFFFFFU), Int64(0)}, Uint64(0xFFFFFFFFFFFFFFFFU)},
      {{Uint64(0xFFFFFFFFFFFFFFFFU), Int64(64)}, Uint64(0)},
      {{Uint64(0xFFFFFFFFFFFFFFFFU), Int64(1)}, Uint64(0x7FFFFFFFFFFFFFFFU)},
      {{Uint64(0x5555000000000000U), Int64(48)}, Uint64(0x5555)},
      {{Uint64(0x5555), Int64(-1)}, NullUint64(), OUT_OF_RANGE},

      {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(0)},
       Bytes("\xFE\xDC\xBA\x98\x76")},
      {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(40)},
       Bytes("\x00\x00\x00\x00\x00")},
      {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(41)},
       Bytes("\x00\x00\x00\x00\x00")},
      {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(1)},
       Bytes("\x7F\x6E\x5D\x4C\x3B")},
      {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(4)},
       Bytes("\x0F\xED\xCB\xA9\x87")},
      {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(17)},
       Bytes("\x00\x00\x7F\x6E\x5D")},
      {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(24)},
       Bytes("\x00\x00\x00\xFE\xDC")},
      {{Bytes("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"), Int64(64)},
       Bytes("\0\0\0\0\0\0\0\0\xFF\xFF\xFF\xFF")},
      {{Bytes("\xFE\xDC\xBA\x98\x76"), Int64(-1)}, NullBytes(), OUT_OF_RANGE},
      // Empty input.
      {{Bytes(""), Int64(0)}, Bytes("")},
      {{Bytes(""), Int64(10)}, Bytes("")},
  };
}

std::vector<QueryParamsWithResult> GetFunctionTestsBitCount() {
  return {
      {{NullInt32()}, NullInt64()},
      {{NullInt64()}, NullInt64()},
      {{NullUint64()}, NullInt64()},
      {{NullBytes()}, NullInt64()},

      {{Int32(0)}, Int64(0)},
      {{Int32(-1)}, Int64(32)},
      {{Int32(-2)}, Int64(31)},
      {{Int32(0xFFFF)}, Int64(16)},
      {{Int32(0xFFFFFF)}, Int64(24)},
      {{Int32(0xFFFFFFF)}, Int64(28)},
      {{Int32(0x7FFFFFFF)}, Int64(31)},
      {{Int32(0x7F0F0F0F)}, Int64(19)},
      {{Int32(0x88888888)}, Int64(8)},

      {{Uint32(0)}, Int64(0)},
      {{Uint32(0xFFFF)}, Int64(16)},
      {{Uint32(0xFFFFFF)}, Int64(24)},
      {{Uint32(0xFFFFFFF)}, Int64(28)},
      {{Uint32(0x7FFFFFFF)}, Int64(31)},
      {{Uint32(0xFFFFFFFFU)}, Int64(32)},
      {{Uint32(0x7F0F0F0F)}, Int64(19)},
      {{Uint32(0x88888888)}, Int64(8)},

      {{Int64(0)}, Int64(0)},
      {{Int64(-1)}, Int64(64)},
      {{Int64(-2)}, Int64(63)},
      {{Int64(0xFFFF)}, Int64(16)},
      {{Int64(0xFFFFFF)}, Int64(24)},
      {{Int64(0xFFFFFFF)}, Int64(28)},
      {{Int64(0x7FFFFFFF)}, Int64(31)},
      {{Int64(0xFFFFFFFFL)}, Int64(32)},
      {{Int64(0xFFFFFFFFFFL)}, Int64(40)},
      {{Int64(0xFFFFFFFFFFFFFFL)}, Int64(56)},
      {{Int64(0xFFFFFFFFFFFFFFFL)}, Int64(60)},
      {{Int64(0x7FFFFFFFFFFFFFFFL)}, Int64(63)},

      {{Uint64(0)}, Int64(0)},
      {{Uint64(-1)}, Int64(64)},
      {{Uint64(-2)}, Int64(63)},
      {{Uint64(0xFFFF)}, Int64(16)},
      {{Uint64(0xFFFFFF)}, Int64(24)},
      {{Uint64(0xFFFFFFF)}, Int64(28)},
      {{Uint64(0x7FFFFFFF)}, Int64(31)},
      {{Uint64(0xFFFFFFFFUL)}, Int64(32)},
      {{Uint64(0xFFFFFFFFFFUL)}, Int64(40)},
      {{Uint64(0xFFFFFFFFFFFFFFUL)}, Int64(56)},
      {{Uint64(0xFFFFFFFFFFFFFFFUL)}, Int64(60)},
      {{Uint64(0x7FFFFFFFFFFFFFFFUL)}, Int64(63)},
      {{Uint64(0xFFFFFFFFFFFFFFFFUL)}, Int64(64)},

      {{Bytes("")}, Int64(0)},
      {{Bytes("\x00")}, Int64(0)},
      {{Bytes("\xFF")}, Int64(8)},
      {{Bytes("\x78")}, Int64(4)},
      {{Bytes("\x00\x00")}, Int64(0)},
      {{Bytes("\xFF\xFF")}, Int64(16)},
      {{Bytes("\xFF\x00")}, Int64(8)},
      {{Bytes("\x00\xFF")}, Int64(8)},
      {{Bytes("\x12\x34")}, Int64(5)},
      {{Bytes("\x01\x02\x03\x04\x05\x06\x07\x08")}, Int64(13)},
      {{Bytes("\x01\x02\x03\x04\x05\x06\x07\x08\x09")}, Int64(15)},
      {{Bytes("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a")}, Int64(17)},
      {{Bytes("\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b")}, Int64(20)},
      {{Bytes("\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF")}, Int64(96)},
  };
}

std::vector<QueryParamsWithResult> GetFunctionTestsAtOffset() {
  const Value int64_array =
      Value::Array(Int64ArrayType(), {Int64(10), Int64(11)});
  const Value string_array =
      Value::Array(StringArrayType(), {String("foo"), String("bar")});
  const StructType* struct_type = SimpleStructType();  // a: string, b: int32_t
  const ArrayType* array_struct_type;
  ZETASQL_CHECK_OK(type_factory()->MakeArrayType(struct_type, &array_struct_type));
  const Value struct0 = Value::Struct(struct_type, {String("foo"), Int32(0)});
  const Value struct1 = Value::Struct(struct_type, {String("bar"), Int32(1)});
  const Value struct_array =
      Value::Array(array_struct_type, {struct0, struct1});
  return {
    {{int64_array, Int64(-1)}, NullInt64(), OUT_OF_RANGE},
    {{int64_array, Int64(0)}, Int64(10)},
    {{int64_array, Int64(1)}, Int64(11)},
    {{int64_array, Int64(2)}, NullInt64(), OUT_OF_RANGE},
    {{string_array, Int64(-1)}, NullString(), OUT_OF_RANGE},
    {{string_array, Int64(0)}, String("foo")},
    {{string_array, Int64(1)}, String("bar")},
    {{string_array, Int64(2)}, NullString(), OUT_OF_RANGE},
    {{struct_array, Int64(-1)}, Null(struct_type), OUT_OF_RANGE},
    {{struct_array, Int64(0)}, struct0},
    {{struct_array, Int64(1)}, struct1},
    {{struct_array, Int64(2)}, Null(struct_type), OUT_OF_RANGE},
  };
}

std::vector<QueryParamsWithResult> GetFunctionTestsSafeAtOffset() {
  // Use the same tests as above, but return null rather than an error when the
  // position is out of bounds.
  std::vector<QueryParamsWithResult> offset_tests = GetFunctionTestsAtOffset();
  for (auto& offset_test : offset_tests) {
    QueryParamsWithResult::ResultMap new_result_map = offset_test.results();
    for (auto& result : new_result_map) {
      result.second.status = absl::OkStatus();
    }
    offset_test.set_results(new_result_map);
  }
  return offset_tests;
}

std::vector<QueryParamsWithResult> GetFunctionTestsIf() {
  std::vector<QueryParamsWithResult> result;
  for (const auto& v : GetRowsOfValues()) {
    result.push_back({{NullBool(), v[0], v[1]}, v[1]});
    result.push_back({{False(), v[0], v[1]}, v[1]});
    result.push_back({{True(), v[0], v[1]}, v[0]});
    result.push_back({{NullBool(), v[1], v[0]}, v[0]});
    result.push_back({{False(), v[1], v[0]}, v[0]});
    result.push_back({{True(), v[1], v[0]}, v[1]});
  }
  WrapNumericTestCases(&result);
  WrapBigNumericTestCases(&result);
  return result;
}

std::vector<QueryParamsWithResult> GetFunctionTestsIfNull() {
  std::vector<QueryParamsWithResult> result;
  for (const auto& v : GetRowsOfValues()) {
    result.push_back({{Null(v[0].type()), v[0]}, v[0]});
    result.push_back({{v[0], v[1]}, v[0]});
    result.push_back({{v[1], v[0]}, v[1]});
  }
  WrapNumericTestCases(&result);
  WrapBigNumericTestCases(&result);
  return result;
}

// Builds test cases with FEATURE_V_1_1_ARRAY_EQUALITY option turned on/off.
static QueryParamsWithResult BuildArrayEqualityQueryParamsWithResult(
    const std::vector<ValueConstructor>& arguments,
    const ValueConstructor& result,
    const Value& null_value) {
  return QueryParamsWithResult(
      arguments,
      {{QueryParamsWithResult::kEmptyFeatureSet,
        QueryParamsWithResult::Result(null_value, OUT_OF_RANGE)},
       {{FEATURE_V_1_1_ARRAY_EQUALITY},
           QueryParamsWithResult::Result(result)}});
}

std::vector<QueryParamsWithResult> GetFunctionTestsNullIf() {
  std::vector<QueryParamsWithResult> result;
  for (const auto& v : GetRowsOfValues()) {
    const Type* type = v[0].type();
    Value null_value = Null(type);
    if (type->IsProto()) {
      // SQL equality is not defined for protos.
      result.push_back({{v[0], v[0]}, null_value, OUT_OF_RANGE});
      continue;
    }
    if (type->IsArray()) {
      result.push_back(BuildArrayEqualityQueryParamsWithResult(
          {null_value, v[0]}, null_value, null_value));
      result.push_back(BuildArrayEqualityQueryParamsWithResult(
          {v[0], null_value}, v[0], null_value));
      result.push_back(BuildArrayEqualityQueryParamsWithResult(
          {v[0], v[1]}, v[0], null_value));
      result.push_back(BuildArrayEqualityQueryParamsWithResult(
          {v[1], v[0]}, v[1], null_value));
      result.push_back(BuildArrayEqualityQueryParamsWithResult(
          {v[0], v[0]}, null_value, null_value));
      result.push_back(BuildArrayEqualityQueryParamsWithResult(
          {v[1], v[1]}, null_value, null_value));
      continue;
    }
    result.push_back({{null_value, v[0]}, null_value});
    result.push_back({{v[0], null_value}, v[0]});
    result.push_back({{v[0], v[1]}, v[0]});
    result.push_back({{v[1], v[0]}, v[1]});
    result.push_back({{v[0], v[0]}, null_value});
    result.push_back({{v[1], v[1]}, null_value});
  }
  WrapNumericTestCases(&result);
  WrapBigNumericTestCases(&result);
  return result;
}

std::vector<QueryParamsWithResult> GetFunctionTestsCoalesce() {
  std::vector<QueryParamsWithResult> result;
  for (const auto& v : GetRowsOfValues()) {
    Value null_value = Null(v[0].type());
    result.push_back({{null_value}, null_value});
    result.push_back({{v[0], null_value}, v[0]});
    result.push_back({{null_value, v[0]}, v[0]});
    result.push_back({{null_value, v[0], v[1]}, v[0]});
    result.push_back({{null_value, v[1], v[0]}, v[1]});
    result.push_back({{null_value, v[0], null_value, v[1]}, v[0]});
    result.push_back({{null_value, v[1], null_value, v[0]}, v[1]});
    result.push_back({{v[0], v[1]}, v[0]});
    result.push_back({{v[1], v[0]}, v[1]});
  }
  WrapNumericTestCases(&result);
  WrapBigNumericTestCases(&result);
  return result;
}


std::vector<FunctionTestCall> GetArrayConcatTests() {
  const Value empty_array = Value::EmptyArray(Int32ArrayType());
  const Value null_array = Value::Null(Int32ArrayType());
  const Value array_12 = Value::Array(Int32ArrayType(), {Int32(1), Int32(2)});
  const Value array_23 = Value::Array(Int32ArrayType(), {Int32(2), Int32(3)});
  const Value array_3 = Value::Array(Int32ArrayType(), {Int32(3)});
  const Value array_1223 = Value::Array(
      Int32ArrayType(), {Int32(1), Int32(2), Int32(2), Int32(3)});
  const Value array_2312 = Value::Array(
      Int32ArrayType(), {Int32(2), Int32(3), Int32(1), Int32(2)});
  const Value array_23123 = Value::Array(
      Int32ArrayType(), {Int32(2), Int32(3), Int32(1), Int32(2), Int32(3)});
  const Value array_ab = Value::Array(StringArrayType(),
                                      {String("a"), String("b")});
  const Value array_c = Value::Array(StringArrayType(), {String("c")});
  const Value array_abc = Value::Array(StringArrayType(),
                                      {String("a"), String("b"), String("c")});
  return {
      // array_concat(array...) -> array
      {"array_concat", {empty_array}, empty_array},
      {"array_concat", {empty_array, empty_array}, empty_array},
      {"array_concat", {empty_array, null_array}, null_array},
      {"array_concat", {null_array}, null_array},
      {"array_concat", {array_12}, array_12},
      {"array_concat", {empty_array, array_12}, array_12},
      {"array_concat", {array_12, empty_array}, array_12},
      {"array_concat", {null_array, array_12}, null_array},
      {"array_concat", {array_12, array_23}, array_1223},
      {"array_concat", {array_23, array_12}, array_2312},
      {"array_concat", {array_23, array_12, array_3}, array_23123},
      {"array_concat", {array_ab}, array_ab},
      {"array_concat", {array_ab, array_c}, array_abc},
  };
}

std::vector<FunctionTestCall> GetFunctionTestsArray() {
  const Value array_ab = Value::Array(StringArrayType(),
                                      {String("a"), String("b")});
  const Value array_c = Value::Array(StringArrayType(), {String("c")});
  const Value array_abc = Value::Array(StringArrayType(),
                                      {String("a"), String("b"), String("c")});
  const Value array_ab_nulls =
      Value::Array(StringArrayType(),
                   {NullString(), String("a"), NullString(), String("b")});
  const Value array_empty_string = Value::Array(StringArrayType(),
                                                {String("")});
  const Value array_empty_string_2 = Value::Array(StringArrayType(),
                                                  {String(""), String("")});
  const Value array_empty_string_3 = Value::Array(StringArrayType(),
                                                  {String("a"), String("")});
  const Value array_empty_string_4 = Value::Array(StringArrayType(),
                                                  {String(""), String("b")});
  const Value array_empty_string_5 =
      Value::Array(StringArrayType(), {String(""), String("b"), String("")});
  const Value array_empty_string_6 =
      Value::Array(StringArrayType(),
                   {String("a"), String(""), String(""), String("b")});

  const Value array_ab_bytes = Value::Array(
      BytesArrayType(), {Bytes("a"), Bytes("b")});
  const Value array_c_bytes = Value::Array(BytesArrayType(), {Bytes("c")});
  const Value array_abc_bytes = Value::Array(
      BytesArrayType(), {Bytes("a"), Bytes("b"), Bytes("c")});
  const Value array_ab_nulls_bytes =
      Value::Array(BytesArrayType(),
                   {NullBytes(), Bytes("a"), NullBytes(), Bytes("b")});
  const Value array_empty_bytes = Value::Array(BytesArrayType(), {Bytes("")});

  const StructType* struct_type = SimpleStructType();  // a: string, b: int32_t
  const Value struct0 = Value::Struct(struct_type, {String("foo"), Int32(0)});
  const Value struct1 = Value::Struct(struct_type, {String("bar"), Int32(1)});
  const Value struct2 = Value::Struct(struct_type, {String("baz"), Int32(2)});
  const ArrayType* array_struct_type = MakeArrayType(struct_type);

  std::vector<FunctionTestCall> results = {
      // array_to_string -> string
      {"array_to_string", {Null(StringArrayType()), String(",")}, NullString()},
      {"array_to_string", {array_ab, NullString()}, NullString()},
      {"array_to_string", {array_ab, String(","), NullString()}, NullString()},
      {"array_to_string",
       {EmptyArray(StringArrayType()), String(",")},
       String("")},
      {"array_to_string", {array_empty_string, String(",")}, String("")},
      {"array_to_string", {array_empty_string_2, String(",")}, String(",")},
      {"array_to_string", {array_empty_string_3, String(",")}, String("a,")},
      {"array_to_string", {array_empty_string_4, String(",")}, String(",b")},
      {"array_to_string", {array_empty_string_5, String(",")}, String(",b,")},
      {"array_to_string", {array_empty_string_6, String(",")}, String("a,,,b")},

      {"array_to_string", {array_c, String(",")}, String("c")},
      {"array_to_string", {array_abc, String(",")}, String("a,b,c")},
      {"array_to_string", {array_abc, String("+!+")}, String("a+!+b+!+c")},
      {"array_to_string", {array_abc, String("")}, String("abc")},
      {"array_to_string", {array_ab_nulls, String(",")}, String("a,b")},
      {"array_to_string",
       {array_ab_nulls, String(","), String("")},
       String(",a,,b")},
      {"array_to_string",
       {array_ab_nulls, String(","), String("*")},
       String("*,a,*,b")},
      {"array_to_string",
       {array_ab_nulls, String(","), String("<null>")},
       String("<null>,a,<null>,b")},

      // array_to_string -> bytes
      {"array_to_string", {Null(BytesArrayType()), Bytes(",")}, NullBytes()},
      {"array_to_string", {array_ab_bytes, NullBytes()}, NullBytes()},
      {"array_to_string",
       {array_ab_bytes, Bytes(","), NullBytes()},
       NullBytes()},
      {"array_to_string",
       {EmptyArray(BytesArrayType()), Bytes(",")},
       Bytes("")},
      {"array_to_string", {array_empty_bytes, Bytes(",")}, Bytes("")},
      {"array_to_string", {array_c_bytes, Bytes(",")}, Bytes("c")},
      {"array_to_string", {array_abc_bytes, Bytes(",")}, Bytes("a,b,c")},
      {"array_to_string", {array_abc_bytes, Bytes("\1")}, Bytes("a\1b\1c")},
      {"array_to_string", {array_abc_bytes, Bytes("")}, Bytes("abc")},
      {"array_to_string", {array_ab_nulls_bytes, Bytes(",")}, Bytes("a,b")},
      {"array_to_string",
       {array_ab_nulls_bytes, Bytes(","), Bytes("\2")},
       Bytes("\2,a,\2,b")},

      {"array_reverse", {Null(Int64ArrayType())}, Null(Int64ArrayType())},
      {"array_reverse", {Int64Array({})}, Int64Array({})},
      {"array_reverse", {Int64Array({1})}, Int64Array({1})},
      {"array_reverse",
       {Int64Array({1, 2, 3, 4, 5, 6, 7, 8, 9, 10})},
       Int64Array({10, 9, 8, 7, 6, 5, 4, 3, 2, 1})},
      {"array_reverse",
       {StringArray({"", "foo", "bar", "baz", "foobar"})},
       StringArray({"foobar", "baz", "bar", "foo", ""})},
      {"array_reverse",
       {DoubleArray({3.14, 1.59, -0.0, double_pos_inf, double_neg_inf})},
       DoubleArray({double_neg_inf, double_pos_inf, -0.0, 1.59, 3.14})},
      {"array_reverse",
       {Value::Array(array_struct_type, {struct0, struct1, struct2})},
       Value::Array(array_struct_type, {struct2, struct1, struct0})},

      {"array_is_distinct", {Null(Int64ArrayType())}, NullBool()},
      {"array_is_distinct", {Int64Array({1, 2, 3})}, True()},
      {"array_is_distinct", {Int64Array({1, 1, 1})}, False()},
      {"array_is_distinct", {Array({Int64(1), Int64(2), NullInt64()})}, True()},
      {"array_is_distinct",
       {Array({Int64(1), Int64(1), NullInt64()})},
       False()},
      {"array_is_distinct",
       {Array({Int64(1), NullInt64(), NullInt64()})},
       False()},
      {"array_is_distinct", {StringArray({"foo", "foo"})}, False()},
      {"array_is_distinct",
       {Array({String(""), String("foo"), NullString()})},
       True()},
      {"array_is_distinct", {DoubleArray({0.0, 1.0})}, True()},
      {"array_is_distinct", {DoubleArray({0.0, 0.0})}, False()},
      {"array_is_distinct", {DoubleArray({0.0, double_nan})}, True()},
      {"array_is_distinct", {DoubleArray({double_nan, double_nan})}, False()},
  };
  std::vector<FunctionTestCall> tests_array_concat = GetArrayConcatTests();
  results.insert(results.end(),
                 std::make_move_iterator(tests_array_concat.begin()),
                 std::make_move_iterator(tests_array_concat.end())
  );
  return results;
}

std::vector<QueryParamsWithResult> GetFunctionTestsArrayConcatOperator() {
  std::vector<QueryParamsWithResult> results;
  // array || array -> array
  // Test the test cases of array_concat function.
  for (const FunctionTestCall& function_call : GetArrayConcatTests()) {
    if (function_call.params.params().size() == 2) {
      results.push_back(function_call.params);
    }
  }
  return results;
}

std::vector<FunctionTestCall> GetFunctionTestsBase32() {
  const std::vector<std::pair<Value, Value>> unencoded_and_encoded = {
      {NullBytes(), NullString()},
      {Bytes(""), String("")},
      {Bytes("1"), String("GE======")},
      {Bytes("1a"), String("GFQQ====")},
      {Bytes("12345"), String("GEZDGNBV")},
      {Bytes("123456"), String("GEZDGNBVGY======")},
      {Bytes("1234567890123456"),
       String("GEZDGNBVGY3TQOJQGEZDGNBVGY======")},
  };
  std::vector<FunctionTestCall> tests;
  for (const auto& entry : unencoded_and_encoded) {
    tests.push_back({"to_base32", {entry.first}, entry.second});
    tests.push_back({"from_base32", {entry.second}, entry.first});
  }
  tests.push_back({"from_base32", {String("GE0")}, NullBytes(), OUT_OF_RANGE});
  tests.push_back({"from_base32", {String("12")}, NullBytes(), OUT_OF_RANGE});
  return tests;
}

std::vector<FunctionTestCall> GetFunctionTestsBase64() {
  const std::vector<std::pair<Value, Value>> unencoded_and_encoded = {
      {NullBytes(), NullString()},
      {Bytes(""), String("")},
      {Bytes(" "), String("IA==")},
      {Bytes("abcABC"), String("YWJjQUJD")},
      {Bytes("abcABCжщфЖЩФ"), String("YWJjQUJD0LbRidGE0JbQqdCk")},
      {Bytes("Ḋ"), String("4biK")},
      {Bytes("abca\0b\0c\0"), String("YWJjYQBiAGMA")},
  };
  std::vector<FunctionTestCall> tests;
  for (const auto& entry : unencoded_and_encoded) {
    tests.push_back({"to_base64", {entry.first}, entry.second});
    tests.push_back({"from_base64", {entry.second}, entry.first});
  }
  tests.push_back({"from_base64", {String("====")}, NullBytes(), OUT_OF_RANGE});
  return tests;
}

std::vector<FunctionTestCall> GetFunctionTestsHex() {
  const std::vector<std::pair<Value, Value>> unencoded_and_encoded = {
      {NullBytes(), NullString()},
      {Bytes(""), String("")},
      {Bytes(" "), String("20")},
      {Bytes("abcABC"), String("616263414243")},
      {Bytes("abcABCжщфЖЩФ"), String("616263414243d0b6d189d184d096d0a9d0a4")},
      {Bytes("\0\0a\ff\xee"), String("0000610c66ee")},
      {Bytes("\x01\x23\x45\x67\x89\xAB\xCD\xEF\x55\xAA"),
       String("0123456789abcdef55aa")},
      {Bytes("\xFE\xDC\xBA\x98\x76\x54\x32\x10\xAA\x55"),
       String("fedcba9876543210aa55")},
  };
  std::vector<FunctionTestCall> tests;
  for (const auto& entry : unencoded_and_encoded) {
    tests.push_back({"to_hex", {entry.first}, entry.second});
    tests.push_back({"from_hex", {entry.second}, entry.first});
  }
  tests.push_back({"from_hex", {String("G")}, NullBytes(), OUT_OF_RANGE});
  tests.push_back({"from_hex", {String("123g321")}, NullBytes(), OUT_OF_RANGE});
  tests.push_back(
      {"from_hex", {String("abcde00011-")}, NullBytes(), OUT_OF_RANGE});
  tests.push_back(
      {"from_hex", {String("abcABCжщфЖЩФ")}, NullBytes(), OUT_OF_RANGE});
  return tests;
}

std::vector<FunctionTestCall> GetFunctionTestsCodePoints() {
  const Value null_array = Null(types::Int64ArrayType());

  // Contains all ASCII characters with values in the range [0, 255].
  Value all_ascii_characters;
  // Elements are numbers from 0 to 255.
  Value all_ascii_characters_array;
  {
    std::string all_ascii_characters_string(255, 'a');
    std::iota(all_ascii_characters_string.begin(),
              all_ascii_characters_string.end(),
              std::numeric_limits<char>::min());
    all_ascii_characters = Bytes(all_ascii_characters_string);

    std::vector<int64_t> all_ascii_characters_vector(255);
    std::iota(all_ascii_characters_vector.begin(),
              all_ascii_characters_vector.end(), 0);
    all_ascii_characters_array =
        values::Int64Array(all_ascii_characters_vector);
  }

  const std::vector<std::pair<Value, Value>> value_and_codepoints = {
      {NullBytes(), null_array},
      {NullString(), null_array},
      {Bytes(""), values::Int64Array({})},
      {String(""), values::Int64Array({})},
      {Bytes(" "), values::Int64Array({32})},
      {String(" "), values::Int64Array({32})},
      {Bytes("abcABC"), values::Int64Array({97, 98, 99, 65, 66, 67})},
      {String("abcABC"), values::Int64Array({97, 98, 99, 65, 66, 67})},
      {String("abcABCжщфЖЩФ"),
       values::Int64Array(
           {97, 98, 99, 65, 66, 67, 1078, 1097, 1092, 1046, 1065, 1060})},
      {String("Ḋ"), values::Int64Array({7690})},
      {Bytes("abca\0\1cde"),
       values::Int64Array({97, 98, 99, 97, 0, 1, 99, 100, 101})},
      // Note that the null character is not interchange valid, but can be part
      // of structurally valid UTF8 strings.
      {String("abca\0\1cde"),
       values::Int64Array({97, 98, 99, 97, 0, 1, 99, 100, 101})},
      {String("абвгд"), values::Int64Array({1072, 1073, 1074, 1075, 1076})},
      // Borders of valid codepoint ranges, which are [0, 0xD800) and
      // [0xE000, 0x10FFFF]. 0 is tested above.
      {String("\uD7FE"
              "\uD7FF"),
       values::Int64Array({0xD7FE, 0xD7FF})},
      {String("\uE000"
              "\uE001"
              "\U0010FFFE"
              "\U0010FFFF"),
       values::Int64Array({0xE000, 0xE001, 0x10FFFE, 0x10FFFF})},
      {all_ascii_characters, all_ascii_characters_array},
  };
  std::vector<FunctionTestCall> tests;
  for (const auto& entry : value_and_codepoints) {
    tests.push_back({"to_code_points", {entry.first}, entry.second});
    if (entry.first.type()->IsBytes()) {
      tests.push_back({"code_points_to_bytes", {entry.second}, entry.first});
    } else {
      tests.push_back({"code_points_to_string", {entry.second}, entry.first});
    }
  }

  // Error cases.
  // The C++ compiler rejects Unicode literals in strings that aren't valid
  // codepoints, so we have to construct them "manually".
  {
    std::string invalid_codepoint_string;
    // The first character is a valid codepoint.
    invalid_codepoint_string.push_back(0xD7);
    invalid_codepoint_string.push_back('\xFF');
    // The second is not.
    invalid_codepoint_string.push_back(0xD8);
    invalid_codepoint_string.push_back('\xFF');

    tests.push_back({"to_code_points",
                     {String(invalid_codepoint_string)},
                     null_array,
                     OUT_OF_RANGE});
  }

  {
    std::string invalid_codepoint_string;
    // The first character is a valid codepoint.
    invalid_codepoint_string.push_back(0xE0);
    invalid_codepoint_string.push_back(0x00);
    // The second is not.
    invalid_codepoint_string.push_back(0xDF);
    invalid_codepoint_string.push_back('\xFF');

    tests.push_back({"to_code_points",
                     {String(invalid_codepoint_string)},
                     null_array,
                     OUT_OF_RANGE});
  }

  {
    std::string invalid_codepoint_string;
    // Invalid three-byte codepoint (above the valid range).
    invalid_codepoint_string.push_back(0x11);
    invalid_codepoint_string.push_back('\xFF');
    invalid_codepoint_string.push_back('\xFF');

    tests.push_back({"to_code_points",
                     {String(invalid_codepoint_string)},
                     null_array,
                     OUT_OF_RANGE});
  }

  // Invalid ASCII values.
  tests.push_back({"code_points_to_bytes",
                   {values::Int64Array({0, -1})},
                   values::NullBytes(),
                   OUT_OF_RANGE});
  tests.push_back({"code_points_to_bytes",
                   {values::Int64Array({256, 10})},
                   values::NullBytes(),
                   OUT_OF_RANGE});
  tests.push_back({"code_points_to_bytes",
                   {values::Int64Array({0, 1, 512})},
                   values::NullBytes(),
                   OUT_OF_RANGE});

  // Invalid codepoints.
  tests.push_back({"code_points_to_string",
                   {values::Int64Array({0, -1})},
                   values::NullString(),
                   OUT_OF_RANGE});
  tests.push_back({"code_points_to_string",
                   {values::Int64Array({-100})},
                   values::NullString(),
                   OUT_OF_RANGE});
  tests.push_back({"code_points_to_string",
                   {values::Int64Array({0, 1, 0xD800})},
                   values::NullString(),
                   OUT_OF_RANGE});
  tests.push_back({"code_points_to_string",
                   {values::Int64Array({10, 100, 0x10FFFF + 1})},
                   values::NullString(),
                   OUT_OF_RANGE});
  tests.push_back({"code_points_to_string",
                   {values::Int64Array({std::numeric_limits<int64_t>::max()})},
                   values::NullString(),
                   OUT_OF_RANGE});

  return tests;
}

std::vector<FunctionTestCall> GetFunctionTestsPadding() {
  std::vector<FunctionTestCall> tests = {
      {"lpad_bytes",
       {Bytes("google"), Int64(-8), Bytes("")},
       NullBytes(),
       OUT_OF_RANGE},
      {"lpad_bytes",
       {Bytes("goog"), Int64(10), Bytes("")},
       NullBytes(),
       OUT_OF_RANGE},
      {"lpad_bytes", {Bytes("abcdef"), Int64(0), Bytes("defgh")}, ""},
      {"lpad_bytes", {Bytes("abcdef"), Int64(6), Bytes("defgh")}, "abcdef"},
      {"lpad_bytes", {Bytes("abcdef"), Int64(4), Bytes("defgh")}, "abcd"},
      {"lpad_bytes", {Bytes("abcdef"), Int64(3), Bytes("defgh")}, "abc"},
      {"lpad_bytes", {Bytes("abcde"), Int64(4), Bytes("defgh")}, "abcd"},
      {"lpad_bytes", {Bytes("abcde"), Int64(3), Bytes("defgh")}, "abc"},
      {"lpad_bytes", {Bytes("abc"), Int64(5), Bytes("defgh")}, "deabc"},
      {"lpad_bytes", {Bytes("abc"), Int64(7), Bytes("defg")}, "defgabc"},
      {"lpad_bytes", {Bytes("abc"), Int64(4), Bytes("def")}, "dabc"},
      {"lpad_bytes", {Bytes("abc"), Int64(10), Bytes("defg")}, "defgdefabc"},
      {"lpad_bytes", {Bytes("abcx"), Int64(5), Bytes("defgh")}, "dabcx"},
      {"lpad_bytes", {Bytes("abcx"), Int64(7), Bytes("defg")}, "defabcx"},
      {"lpad_bytes", {Bytes("abcx"), Int64(10), Bytes("defg")}, "defgdeabcx"},
      {"lpad_bytes", {Bytes("abc"), Int64(7), Bytes("-")}, "----abc"},
      {"lpad_bytes", {Bytes(""), Int64(7), Bytes("-")}, "-------"},
      {"lpad_bytes", {Bytes(""), Int64(7), Bytes("def")}, "defdefd"},

      {"lpad_bytes", {Bytes("abc"), Int64(7)}, "    abc"},
      {"lpad_bytes", {Bytes(""), Int64(7)}, "       "},
      {"lpad_bytes", {Bytes("abcx"), Int64(10)}, "      abcx"},

      {"rpad_bytes",
       {Bytes("google"), Int64(-8), Bytes("")},
       NullBytes(),
       OUT_OF_RANGE},
      {"rpad_bytes",
       {Bytes("goog"), Int64(10), Bytes("")},
       NullBytes(),
       OUT_OF_RANGE},
      {"rpad_bytes", {Bytes("abcdef"), Int64(0), Bytes("defgh")}, ""},
      {"rpad_bytes", {Bytes("abcdef"), Int64(6), Bytes("defgh")}, "abcdef"},
      {"rpad_bytes", {Bytes("abcdef"), Int64(4), Bytes("defgh")}, "abcd"},
      {"rpad_bytes", {Bytes("abcdef"), Int64(3), Bytes("defgh")}, "abc"},
      {"rpad_bytes", {Bytes("abc"), Int64(5), Bytes("defgh")}, "abcde"},
      {"rpad_bytes", {Bytes("abc"), Int64(7), Bytes("defg")}, "abcdefg"},
      {"rpad_bytes", {Bytes("abc"), Int64(4), Bytes("def")}, "abcd"},
      {"rpad_bytes", {Bytes("abc"), Int64(10), Bytes("defg")}, "abcdefgdef"},
      {"rpad_bytes", {Bytes("abcx"), Int64(5), Bytes("defgh")}, "abcxd"},
      {"rpad_bytes", {Bytes("abcx"), Int64(7), Bytes("defg")}, "abcxdef"},
      {"rpad_bytes", {Bytes("abcx"), Int64(8), Bytes("def")}, "abcxdefd"},
      {"rpad_bytes", {Bytes("abcx"), Int64(10), Bytes("defg")}, "abcxdefgde"},
      {"rpad_bytes", {Bytes("abc"), Int64(7), Bytes("-")}, "abc----"},
      {"rpad_bytes", {Bytes(""), Int64(7), Bytes("-")}, "-------"},
      {"rpad_bytes", {Bytes(""), Int64(7), Bytes("def")}, "defdefd"},

      {"rpad_bytes", {Bytes("abc"), Int64(7)}, "abc    "},
      {"rpad_bytes", {Bytes(""), Int64(7)}, "       "},
      {"rpad_bytes", {Bytes("abcx"), Int64(10)}, "abcx      "},

      {"rpad_string",
       {"者不終朝ef而", Int64(-8), ""},
       NullString(),
       OUT_OF_RANGE},
      {"rpad_string",
       {"者不終朝ef而", Int64(10), ""},
       NullString(),
       OUT_OF_RANGE},
      {"rpad_string", {"abcdef", Int64(0), "defgh"}, ""},
      {"rpad_string", {"abcdef", Int64(6), "defgh"}, "abcdef"},
      {"rpad_string", {"abcdef", Int64(4), "defgh"}, "abcd"},
      {"rpad_string", {"abcdef", Int64(3), "defgh"}, "abc"},
      {"rpad_string", {"abc", Int64(5), "defgh"}, "abcde"},
      {"rpad_string", {"abc", Int64(7), "defg"}, "abcdefg"},
      {"rpad_string", {"abc", Int64(4), "def"}, "abcd"},
      {"rpad_string", {"abc", Int64(10), "defg"}, "abcdefgdef"},
      {"rpad_string", {"abcx", Int64(5), "defgh"}, "abcxd"},
      {"rpad_string", {"abcx", Int64(7), "defg"}, "abcxdef"},
      {"rpad_string", {"abcx", Int64(8), "def"}, "abcxdefd"},
      {"rpad_string", {"abcx", Int64(10), "defg"}, "abcxdefgde"},
      {"rpad_string", {"abc", Int64(7), "-"}, "abc----"},
      {"rpad_string", {"", Int64(7), "-"}, "-------"},
      {"rpad_string", {"", Int64(7), "def"}, "defdefd"},
      {"rpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(6), "智者不終朝"}, "¼¼¼𠈓𠈓𠈓"},
      {"rpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(5), "智者不終朝"}, "¼¼¼𠈓𠈓"},
      {"rpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(7), "智者不終朝"}, "¼¼¼𠈓𠈓𠈓智"},
      {"rpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(10), "智者朝"}, "¼¼¼𠈓𠈓𠈓智者朝智"},

      {"rpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(7)}, "¼¼¼𠈓𠈓𠈓 "},
      {"rpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(10)}, "¼¼¼𠈓𠈓𠈓    "},
      {"rpad_string", {"", Int64(5)}, "     "},

      {"lpad_string", {"google", Int64(-8), ""}, NullString(), OUT_OF_RANGE},
      {"lpad_string", {"goog", Int64(10), ""}, NullString(), OUT_OF_RANGE},
      {"lpad_string", {"abcdef", Int64(0), "defgh"}, ""},
      {"lpad_string", {"abcdef", Int64(6), "defgh"}, "abcdef"},
      {"lpad_string", {"abcdef", Int64(4), "defgh"}, "abcd"},
      {"lpad_string", {"abcdef", Int64(3), "defgh"}, "abc"},
      {"lpad_string", {"abcde", Int64(4), "defgh"}, "abcd"},
      {"lpad_string", {"abcde", Int64(3), "defgh"}, "abc"},
      {"lpad_string", {"abc", Int64(5), "defgh"}, "deabc"},
      {"lpad_string", {"abc", Int64(7), "defg"}, "defgabc"},
      {"lpad_string", {"abc", Int64(4), "def"}, "dabc"},
      {"lpad_string", {"abc", Int64(10), "defg"}, "defgdefabc"},
      {"lpad_string", {"abcx", Int64(5), "defgh"}, "dabcx"},
      {"lpad_string", {"abcx", Int64(7), "defg"}, "defabcx"},
      {"lpad_string", {"abcx", Int64(10), "defg"}, "defgdeabcx"},
      {"lpad_string", {"abc", Int64(7), "-"}, "----abc"},
      {"lpad_string", {"", Int64(7), "-"}, "-------"},
      {"lpad_string", {"", Int64(7), "def"}, "defdefd"},
      {"lpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(6), "智者不終朝"}, "¼¼¼𠈓𠈓𠈓"},
      {"lpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(5), "智者不終朝"}, "¼¼¼𠈓𠈓"},
      {"lpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(7), "智者不終朝"}, "智¼¼¼𠈓𠈓𠈓"},
      {"lpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(10), "智者朝"}, "智者朝智¼¼¼𠈓𠈓𠈓"},
      {"lpad_string", {"¼¼𠈓𠈓", Int64(10), "智者朝"}, "智者朝智者朝¼¼𠈓𠈓"},

      {"lpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(7)}, " ¼¼¼𠈓𠈓𠈓"},
      {"lpad_string", {"¼¼¼𠈓𠈓𠈓", Int64(10)}, "    ¼¼¼𠈓𠈓𠈓"},
      {"lpad_string", {"", Int64(5)}, "     "},
  };

  {
    std::string bad_utf8;

    bad_utf8.push_back(0xD7);
    bad_utf8.push_back('\xFF');
    bad_utf8.push_back(0xD8);
    bad_utf8.push_back('\xFF');

    tests.push_back({"lpad_string",
                     {"valid", Int64(10), bad_utf8},
                     NullString(),
                     OUT_OF_RANGE});

    tests.push_back({"lpad_string",
                     {bad_utf8, Int64(10), "valid"},
                     NullString(),
                     OUT_OF_RANGE});

    tests.push_back({"rpad_string",
                     {"valid", Int64(10), bad_utf8},
                     NullString(),
                     OUT_OF_RANGE});

    tests.push_back({"rpad_string",
                     {bad_utf8, Int64(10), "valid"},
                     NullString(),
                     OUT_OF_RANGE});
  }
  return tests;
}

std::vector<FunctionTestCall> GetFunctionTestsRepeat() {
  return {
      {"repeat", {Bytes("google"), Int64(-8)}, NullString(), OUT_OF_RANGE},
      {"repeat", {Bytes("abcx"), Int64(0)}, ""},
      {"repeat", {Bytes("abcx"), Int64(1)}, "abcx"},
      {"repeat", {Bytes("abcx"), Int64(2)}, "abcxabcx"},
      {"repeat", {Bytes("abcx"), Int64(3)}, "abcxabcxabcx"},
      {"repeat", {Bytes("abc"), Int64(2)}, "abcabc"},
      {"repeat", {Bytes(""), Int64(3)}, ""},
      {"repeat", {Bytes(""), Int64(2147483648)}, ""},
      {"repeat", {"", Int64(100)}, ""},
      {"repeat", {"¼¼¼𠈓𠈓𠈓", Int64(1)}, "¼¼¼𠈓𠈓𠈓"},
      {"repeat", {"¼¼¼a", Int64(2)}, "¼¼¼a¼¼¼a"},
      {"repeat", {"¼¼¼a", Int64(3)}, "¼¼¼a¼¼¼a¼¼¼a"},
      {"repeat", {"¼¼¼a", Int64((1 << 28))}, NullString(), OUT_OF_RANGE},
      {"repeat",
       {"¼¼¼a", Int64(std::numeric_limits<int64_t>::max())},
       NullString(),
       OUT_OF_RANGE},
  };
}

std::vector<FunctionTestCall> GetFunctionTestsReverse() {
  return {
      // String inputs.
      {"reverse", {NullString()}, NullString()},
      {"reverse", {String("")}, String("")},
      {"reverse", {String("abcABC")}, String("CBAcba")},
      {"reverse", {String("abcABCжщфЖЩФ¼𠈓")}, String("𠈓¼ФЩЖфщжCBAcba")},
      // Byte inputs.
      {"reverse", {NullBytes()}, NullBytes()},
      {"reverse", {Bytes("")}, Bytes("")},
      {"reverse", {Bytes("abcABC")}, Bytes("CBAcba")},
      {"reverse", {Bytes("\0\0\1\2\3\4")}, Bytes("\4\3\2\1\0\0")},
  };
}

std::vector<FunctionTestCall> GetFunctionTestsFromProto() {
  return {
      // Proto3 Timestamp Conversions
      {"from_proto", {Proto3Timestamp(1234, 5000)}, Timestamp(1234000005)},
      {"from_proto",
       {Proto3Timestamp(1391258096, 123450000)},
       Timestamp(1391258096123450)},
      {"from_proto",
       {Proto3Timestamp(962409600, 123456000)},
       Timestamp(962409600123456)},
      {"from_proto",
       {Proto3Timestamp(1391258096, 0)},
       Timestamp(1391258096000000)},
      {"from_proto", {Proto3Timestamp(-50400, 1000)}, Timestamp(-50399999999)},
      {"from_proto",
       {Proto3Timestamp(1391258096, 123450000)},
       Timestamp(1391258096123450)},
      {"from_proto", {Proto3Timestamp(50400, 1000)}, Timestamp(50400000001)},
      {"from_proto",
       {Proto3Timestamp(1232496059, 0)},
       Timestamp(1232496059000000)},
      {"from_proto",
       {Proto3Timestamp(253402300799, 999999999)},
       Timestamp(types::kTimestampMax)},
      {"from_proto",
       {Proto3Timestamp(-62135596800, 0)},
       Timestamp(types::kTimestampMin)},
      {"from_proto", {Proto3Timestamp(123, -1)}, NullTimestamp(), OUT_OF_RANGE},
      {"from_proto",
       {Proto3Timestamp(0, 1000000000)},
       NullTimestamp(),
       OUT_OF_RANGE},
      {"from_proto",
       {Proto3Timestamp(-62135596825, 0)},
       NullTimestamp(),
       OUT_OF_RANGE},

      // Proto3 Date Conversions
      {"from_proto", {Proto3Date(9999, 12, 31)}, DateFromStr("9999-12-31")},
      {"from_proto", {Proto3Date(0001, 1, 1)}, DateFromStr("0001-01-01")},
      {"from_proto", {Proto3Date(1960, 1, 07)}, DateFromStr("1960-01-07")},
      {"from_proto", {Proto3Date(1999, 12, 31)}, DateFromStr("1999-12-31")},
      {"from_proto", {Proto3Date(500, 8, 30)}, DateFromStr("0500-08-30")},
      {"from_proto", {Proto3Date(2016, 2, 29)}, DateFromStr("2016-02-29")},
      {"from_proto", {Proto3Date(2017, 2, 29)}, NullDate(), OUT_OF_RANGE},
      {"from_proto", {Proto3Date(10000, 9, 17)}, NullDate(), OUT_OF_RANGE},
      {"from_proto", {Proto3Date(2017, 11, 31)}, NullDate(), OUT_OF_RANGE},
      {"from_proto", {Proto3Date(2014, 13, 15)}, NullDate(), OUT_OF_RANGE},
      {"from_proto", {Proto3Date(0, 1, 1)}, NullDate(), OUT_OF_RANGE},
      {"from_proto", {Proto3Date(1, 0, 1)}, NullDate(), OUT_OF_RANGE},
      {"from_proto", {Proto3Date(1, 1, 0)}, NullDate(), OUT_OF_RANGE},

      // Proto3 Wrapper Conversions
      {"from_proto",
       {Proto3Wrapper<google::protobuf::Int32Value>(-100)},
       Int32(-100)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::Int32Value>(0)},
       Int32(0)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::Int32Value>(500)},
       Int32(500)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::Int32Value>(int32max)},
       Int32(int32max)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::Int32Value>(int32min)},
       Int32(int32min)},

      {"from_proto",
       {Proto3Wrapper<google::protobuf::Int64Value>(-1000000)},
       Int64(-1000000)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::Int64Value>(0)},
       Int64(0)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::Int64Value>(200000000)},
       Int64(200000000)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::Int64Value>(int64max)},
       Int64(int64max)},

      {"from_proto",
       {Proto3Wrapper<google::protobuf::UInt32Value>(1000000)},
       Uint32(1000000)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::UInt32Value>(0)},
       Uint32(0)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::UInt32Value>(1000000000)},
       Uint32(1000000000)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::UInt32Value>(uint32max)},
       Uint32(uint32max)},

      {"from_proto",
       {Proto3Wrapper<google::protobuf::UInt64Value>(10000000)},
       Uint64(10000000)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::UInt64Value>(0)},
       Uint64(0)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::UInt64Value>(3000000000)},
       Uint64(3000000000)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::UInt64Value>(uint64max)},
       Uint64(uint64max)},

      {"from_proto",
       {Proto3Wrapper<google::protobuf::DoubleValue>(-12345467.89111)},
       Double(-12345467.89111)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::DoubleValue>(0)},
       Double(0)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::DoubleValue>(9876543210.123456)},
       Double(9876543210.123456)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::DoubleValue>(doublemax)},
       Double(doublemax)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::DoubleValue>(doublemin)},
       Double(doublemin)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::DoubleValue>(double_nan)},
       Double(double_nan)},

      {"from_proto",
       {Proto3Wrapper<google::protobuf::FloatValue>(-1234.891f)},
       Float(-1234.891f)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::FloatValue>(0)},
       Float(0)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::FloatValue>(9910.12f)},
       Float(9910.12f)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::FloatValue>(floatmin)},
       Float(floatmin)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::FloatValue>(floatmax)},
       Float(floatmax)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::FloatValue>(float_nan)},
       Float(float_nan)},

      {"from_proto",
       {Proto3Wrapper<google::protobuf::StringValue>("abcdefg")},
       String("abcdefg")},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::StringValue>("")},
       String("")},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::StringValue>("?!#$%^&*!")},
       String("?!#$%^&*!")},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::StringValue>("   ыфabcщ   ")},
       String("   ыфabcщ   ")},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::StringValue>("12356789")},
       String("12356789")},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::BytesValue>(absl::Cord("abcdefg"))},
       Bytes(absl::Cord("abcdefg"))},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::BytesValue>(absl::Cord(""))},
       Bytes(absl::Cord(""))},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::BytesValue>(absl::Cord("\xd7\x00"))},
       Bytes("\xd7")},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::BytesValue>(
           absl::Cord("\xFF\x80\x81xyz\x81\x80\xFF"))},
       Bytes("\xFF\x80\x81xyz\x81\x80\xFF")},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::BytesValue>(absl::Cord("a \0xyza \0"))},
       Bytes("a ")},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::BoolValue>(true)},
       Bool(true)},
      {"from_proto",
       {Proto3Wrapper<google::protobuf::BoolValue>(false)},
       Bool(false)},

      // Idempotent tests
      {"from_proto", {Bool(false)}, Bool(false)},
      {"from_proto", {Bytes("abc")}, Bytes("abc")},
      {"from_proto", {String("abc")}, String("abc")},
      {"from_proto", {Int32(123)}, Int32(123)},
      {"from_proto", {Uint32(123)}, Uint32(123)},
      {"from_proto", {Int64(123)}, Int64(123)},
      {"from_proto", {Uint64(123)}, Uint64(123)},
      {"from_proto", {Double(12.3)}, Double(12.3)},
      {"from_proto", {Float(9910.12f)}, Float(9910.12f)},
      {"from_proto", {DateFromStr("1960-01-07")}, DateFromStr("1960-01-07")},
      {"from_proto", {Timestamp(1234000005)}, Timestamp(1234000005)},
      {"from_proto", {Bool(false)}, Bool(false)},

      // Null input
      {"from_proto", {NullInt64()}, NullInt64()},
      {"from_proto", {Value::Null(Proto3DateType())}, NullDate()},
      {"from_proto", {Value::Null(Proto3TimestampType())}, NullTimestamp()},

      // Invalid argument
      {"from_proto",
       {KitchenSink("int64_key_1: 1 int64_key_2: 2")},
       NullInt64(),
       INVALID_ARGUMENT},
  };
}

static absl::Status FunctionEvalError() {
  return absl::Status(absl::StatusCode::kOutOfRange,
                      "Function Evaluation Error");
}

std::vector<QueryParamsWithResult>  GetFunctionTestsFromProto3TimeOfDay() {
  std::vector<CivilTimeTestCase> test_cases = {
      {{Proto3TimeOfDay(0, 0, 0, 0)}, TimeFromStr("00:00:00")},
      {{{Proto3TimeOfDay(12, 34, 56, 123456)}},
       TimeFromStr("12:34:56.000123"),
       TimeFromStr("12:34:56.000123456", functions::kNanoseconds)},
      {{{Proto3TimeOfDay(23, 59, 59, 999999)}},
       TimeFromStr("23:59:59.000999"),
       TimeFromStr("23:59:59.000999999", functions::kNanoseconds)},
      {{{Proto3TimeOfDay(7, 0, 6, 654321)}},
       TimeFromStr("07:00:06.000654"),
       TimeFromStr("07:00:06.000654321", functions::kNanoseconds)},
      {{{Proto3TimeOfDay(13, 30, 17, 987654)}},
       TimeFromStr("13:30:17.000987"),
       TimeFromStr("13:30:17.000987654", functions::kNanoseconds)},
      {{TimeFromStr("12:34:56.000987")}, TimeFromStr("12:34:56.000987")},
      {{TimeFromStr("12:34:56.000987654", functions::kNanoseconds)},
       TimeFromStr("12:34:56.000987654", functions::kNanoseconds)},
      {{Proto3TimeOfDay(02, 0, 59, 0)}, TimeFromStr("02:00:59")},
      {{Proto3TimeOfDay(02, 0, 60, 0)}, FunctionEvalError(), TimeType()},
      {{Proto3TimeOfDay(02, 0, 30, 1000000000)},
       FunctionEvalError(),
       TimeType()},
      {{Proto3TimeOfDay(24, 0, 0, 0)}, FunctionEvalError(), TimeType()}};

  std::vector<QueryParamsWithResult> result;
  result.reserve(test_cases.size());
  for (const CivilTimeTestCase& test : test_cases) {
    result.push_back(WrapResultForCivilTimeAndNanos(test));
  }

  return result;
}


// To generate the TO_PROTO tests, we take the FROM_PROTO tests and swap
// the argument and result values.  For tests where the FROM_PROTO argument
// is a proto (the normal case), we also add an idempotent TO_PROTO test.
std::vector<FunctionTestCall> GetFunctionTestsToProto() {
  const std::string kFunctionName = "to_proto";
  std::vector<FunctionTestCall> test_cases;
  test_cases.reserve(GetFunctionTestsFromProto().size());
  for (const FunctionTestCall& test : GetFunctionTestsFromProto()) {
    if (!test.params.status().ok() || !test.params.param(0).type()->IsProto() ||
        test.params.result() == Timestamp(types::kTimestampMax)) {
      // Skip FROM_PROTO tests where the argument is not a proto (FROM_PROTO
      // idempotent tests), and tests that return errors.  Also skip tests
      // where the FROM_PROTO result is kTimestampMax (micros precision) as it
      // not possible for TO_PROTO to produce the max Proto3 Timestamp (nanos
      // precision) value from a micros TIMESTAMP.
      continue;
    }
    test_cases.emplace_back(
        kFunctionName, ValueConstructor::FromValues({test.params.param(0)}),
        test.params.param(0));
    test_cases.emplace_back(
        kFunctionName, ValueConstructor::FromValues({test.params.result()}),
        test.params.param(0));
  }

  // Null input
  test_cases.push_back(
      {"to_proto",
       {NullInt64()},
       Null(Proto3Wrapper<google::protobuf::Int64Value>(0).type())});

  // Invalid input
  test_cases.push_back({"to_proto",
                              {zetasql::values::Int64Array({13})},
                              NullInt64(),
                              INVALID_ARGUMENT});

  return test_cases;
}

std::vector<QueryParamsWithResult> GetFunctionTestsToProto3TimeOfDay() {
  std::vector<QueryParamsWithResult> test_cases = {
      {{TimeFromStr("00:00:00")}, Proto3TimeOfDay(0, 0, 0, 0)},
      {{TimeFromStr("12:34:56.000123")}, Proto3TimeOfDay(12, 34, 56, 123000)},
      {{TimeFromStr("23:59:59.000999")}, Proto3TimeOfDay(23, 59, 59, 999000)},
      {{TimeFromStr("07:00:06.000654")}, Proto3TimeOfDay(7, 0, 6, 654000)},
      {{TimeFromStr("13:30:17.000987")}, Proto3TimeOfDay(13, 30, 17, 987000)},
      {{TimeFromStr("02:00:59")}, Proto3TimeOfDay(02, 0, 59, 0)},
      {{Proto3TimeOfDay(13, 30, 17, 987000)},
       Proto3TimeOfDay(13, 30, 17, 987000)}};

  for (auto&& test : test_cases) {
    test = test.WrapWithFeature(FEATURE_V_1_2_CIVIL_TIME);
  }

  std::vector<QueryParamsWithResult> nanos_test_cases = {
      {{TimeFromStr("12:34:56.000123456", functions::kNanoseconds)},
       Proto3TimeOfDay(12, 34, 56, 123456)},
      {{TimeFromStr("23:59:59.000999999", functions::kNanoseconds)},
       Proto3TimeOfDay(23, 59, 59, 999999)},
      {{TimeFromStr("07:00:06.000654321", functions::kNanoseconds)},
       Proto3TimeOfDay(7, 0, 6, 654321)},
      {{TimeFromStr("13:30:17.000987654", functions::kNanoseconds)},
       Proto3TimeOfDay(13, 30, 17, 987654)},
      {{TimeFromStr("13:30:17.000987654", functions::kNanoseconds)},
       Proto3TimeOfDay(13, 30, 17, 987654)},
      {{TimeFromStr("13:30:17.123456789", functions::kNanoseconds)},
       Proto3TimeOfDay(13, 30, 17, 123456789)},
      {{Proto3TimeOfDay(13, 30, 17, 123456789)},
       Proto3TimeOfDay(13, 30, 17, 123456789)}};

  for (auto&& test : nanos_test_cases) {
    test = test.WrapWithFeatureSet(
        {FEATURE_V_1_2_CIVIL_TIME, FEATURE_TIMESTAMP_NANOS});
    test_cases.push_back(test);
  }
  return test_cases;
}

}  // namespace zetasql
